How do I pretty-print JSON in Delphi?
Asked Answered
C

6

16

I am looking for a function that will take a string of JSON as input and format it with line breaks and indentations (tabs).

Example: I have input line:

{"menu": {"header": "JSON viewer", "items": [{"id": "Delphi"},{"id": "Pascal", "label": "Nice tree format"}, null]}}

And want to get a readable result as text:

{
   "menu":{
      "header":"JSON viewer",
      "items":[
       {
         "id":"Delphi"
       },
       {
         "id":"Pascal",
         "label":"Nice tree format"
       },
       null
      ]
   }
}

I found a lot of examples for PHP and C#, but not for Delphi. Could someone help with such a function?

Update - Solution with SuperObject:

function FormatJson (InString: WideString): string; // Input string is "InString"
var
  Json : ISuperObject;
begin
  Json := TSuperObject.ParseString(PWideChar(InString), True);
  Result := Json.AsJson(true, false); //Here comes your result: pretty-print JSON
end;
Carbazole answered 29/8, 2013 at 12:42 Comment(2)
Nice of you to share the answer.Hazelwood
If you simply changed your input parameter type to WideString, you wouldn't need any of that conversion code; the compiler would the equivalent task automatically any time you called FormatJson. Just change the type, and you can replace the first seven lines with Json := TSuperObject.ParseString(PWideChar(InString), True).Carlyn
G
7

Use the superobject library, make sure that you use the latest version from the repository file, not the 1.2.4 ZIP.

Then you can format your TSuperObject object with .AsJSON(true) (the 'true' does the trick).

[ Note that you have no control over the order in which the JSON fields are displayed ]

[ And to create your object from the string: var lJSON : ISuperObject; lJSON := SO(string); ]

Galasyn answered 29/8, 2013 at 12:48 Comment(1)
Your advice worked for me, thanks! Just got a small problem with "TSuperObject.ParseString(mystring, true);" where mystring coud not be a string type but PWideString istead.Carbazole
P
21

If you do not want to use any external library, and you're using a delphi XE5 or newer, there is a very handy TJson.Format() function in the REST.Json unit.

uses json, REST.Json;

{ ... }    

function FormatJSON(json: String): String;
var
  tmpJson: TJsonObject;
begin
  tmpJson := TJSONObject.ParseJSONValue(json);
  Result := TJson.Format(tmpJson);

  FreeAndNil(tmpJson);
end;
Peavey answered 28/6, 2016 at 8:50 Comment(3)
Be aware that as of Delphi Berlin Update 2 the TJson.Format function produces human readable, but not Json compatible output as it does not properly escape anything but double quotes.Stereotaxis
In Tokio tmpJson must be TJsonValue: function FormatJSON(json: String): String; var tmpJson: TJsonValue; begin tmpJson := TJSONObject.ParseJSONValue(json); Result := TJson.Format(tmpJson); FreeAndNil(tmpJson); end;Breeches
Since Delphi 10.3 Rio: REST.Json.TJson.Format is deprecated ("Use TJSONAncestor.Format instead"); See Alex' answer below.Billiebilling
P
8

You may also use the following methods of our Open Source SynCommons.pas unit:

var json,new: RawUTF8;
begin
  json := '{"menu": {"header": "JSON viewer", "items": [{"id": "Delphi"},{"id": "Pascal", "label": "Nice tree format"}, null]}}';
  new := JSONReformat(json,jsonHumanReadable);
  ...

Here new will contain:

{
  "menu": {
    "header": "JSON viewer",
    "items": 
    [
      {
        "id": "Delphi"
      },
      {
        "id": "Pascal",
        "label": "Nice tree format"
      },
      null
    ]
  }
}

If you use the jsonUnquotedPropName format:

  new := JSONReformat(json,jsonUnquotedPropName);

you will get the following extended syntax (similar to the one used in JavaScript or MongoDB shell):

{
  menu: {
    header: "JSON viewer",
    items: 
    [
      {
        id: "Delphi"
      },
      {
        id: "Pascal",
        label: "Nice tree format"
      },
      null
    ]
  }
}

This syntax is accepted as valid input for all the JSON functions of our Open Source framework, as alternative to the default JSON syntax. We found it pretty useful, e.g. for configuration files.

Note that our JSONReformat() function is very fast. It converts the huge 190 MB of unconformatable JSON content from CityLots into 400 MB of beautified JSON (intended and with line fields) in 1.4 seconds. SuperObject is just able to read it in 10 seconds, and uses 1.1 GB just for storing the 190 MB of content. And DBXJSON is not even able to load the data: it consumes all 32 bit memory - under Win64 (XE6), it takes 50 seconds and uses 3 GB of RAM to read the 190 MB of JSON. See this article for some numbers.

Papyraceous answered 22/8, 2014 at 20:29 Comment(1)
Note: Our SynCommons.pas unit works from Delphi 6 up to XE6, in both Win32 and Win64 platforms, and does fully support Unicode, even on the Delphi 7 revision you are still using. In fact, the unit (and this JSONReformat() function) does all the process directly in UTF-8, without any memory allocation of the data into string or widestring. Just use the supplied StringToUTF8() or UTF8ToString() functions to work with your string variables.Papyraceous
G
7

Use the superobject library, make sure that you use the latest version from the repository file, not the 1.2.4 ZIP.

Then you can format your TSuperObject object with .AsJSON(true) (the 'true' does the trick).

[ Note that you have no control over the order in which the JSON fields are displayed ]

[ And to create your object from the string: var lJSON : ISuperObject; lJSON := SO(string); ]

Galasyn answered 29/8, 2013 at 12:48 Comment(1)
Your advice worked for me, thanks! Just got a small problem with "TSuperObject.ParseString(mystring, true);" where mystring coud not be a string type but PWideString istead.Carbazole
A
5

This is a bit old, but if anyone is interested Delphi's native System.JSON unit can do this too. Sample uses a TMemo and a TButton to format the JSON

procedure TForm1.btnFormatJSONClick(Sender: TObject);
const
 DEF_INDENT = 2;
var
 JO : TJSONObject;
begin
 try
  JO := TJSONObject.ParseJSONValue(memoJSON.Text) as TJSONObject;
  memoJSON.Text := JO.Format(DEF_INDENT);
 except
  on E:Exception do
   begin
    MessageDlg('Error in JSON syntax', mtError, [mbOK], 0);
   end;
 end;
end;
Absquatulate answered 1/7, 2020 at 21:38 Comment(2)
FYI Delphi 10.3 or newer is needed for TJSONObject.FormatStonwin
Using the System.JSON unit for formatting JSON is also better than the old deprecated REST.Json method.Gonfalon
R
1

If you're working with Delphi XE or newer, you can use the delphi-xe-json library

function PrettyPrint (aJSON : string) : string;
var
  jo : IJSONObject
begin
  jo := TJSON.NewObject(aJSON);
  result := jo.ToString(true);
end;
Rotten answered 29/8, 2013 at 13:56 Comment(1)
Yeah, thanks for this advice also! I still use Delphi 7 because my project is too big and too old :)Carbazole
C
1

Since Delphi 10.3 Rio, no REST.Json required:

function Format_JSON(Value: String; Indentation: Integer = 4): String; inline;
var
  JV: TJSONValue; // not TJSONObject
begin
  JV := nil;
  try
    try
      JV := TJSONObject.ParseJSONValue(Value);
         // TJSONObject.ParseJSONValue(Value) as TJSONObject cast fails
      Result := JV.Format(Indentation);
    except
      on E: Exception do Log_Exception(E);
    end;
  finally
    FreeAndNil(JV);
  end;
end;
Casting answered 23/7, 2022 at 18:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.