JSONValue to Indented String

坚强是说给别人听的谎言 提交于 2019-12-24 01:55:07

问题


In Delphi XE2, I need to make a function that receives a JSONValue and returns an indented String, much like JSONLint. This JSONValue could be any type of JSON, could be an array, an object, even just a string, so I have to make sure to cover all types with this function. I have no idea where to start.


回答1:


You'll have to do it recursively. Something like this:

const INDENT_SIZE = 2;

procedure PrettyPrintJSON(value: TJSONValue; output: TStrings; indent: integer = 0); forward;

procedure PrettyPrintPair(value: TJSONPair; output: TStrings; last: boolean; indent: integer);
const TEMPLATE = '%s : %s';
var
  line: string;
  newList: TStringList;
begin
  newList := TStringList.Create;
  try
    PrettyPrintJSON(value.JsonValue, newList, indent);
    line := format(TEMPLATE, [value.JsonString.ToString, Trim(newList.Text)]);
  finally
    newList.Free;
  end;

  line := StringOfChar(' ', indent * INDENT_SIZE) + line;
  if not last then
    line := line + ','
  output.add(line);
end;

procedure PrettyPrintJSON(value: TJSONValue; output: TStrings; indent: integer);
var
  i: integer;
begin
  if value is TJSONObject then
  begin
    output.add(StringOfChar(' ', indent * INDENT_SIZE) + '{');
    for i := 0 to TJSONObject(value).size - 1 do
      PrettyPrintPair(TJSONObject(value).Get(i), output, i = TJSONObject(value).size - 1, indent + 1);
    output.add(StringOfChar(' ', indent * INDENT_SIZE) + '}');
  end
  else if value is TJSONArray then
    //left as an exercise to the reader
  else output.add(StringOfChar(' ', indent * INDENT_SIZE) + value.ToString);
end;

This covers the basic principle. WARNING: I wrote this up off the top of my head. It may not be correct or even compile, but it's the general idea. Also, you'll have to come up with your own implementation of printing a JSON array. But this should get you started.




回答2:


I have adopted the code from Mason, did the reader exercise, and put it in a separate unit:

unit uJSONTools;

interface

Uses
  Classes, SysUtils, DBXJSON;

procedure PrettyPrintJSON(JSONValue: TJSONValue; OutputStrings: TStrings; indent: integer = 0);
// Formats JSONValue to an indented structure and adds it to OutputStrings

implementation

const INDENT_SIZE = 2;

procedure PrettyPrintPair(JSONValue: TJSONPair; OutputStrings: TStrings; last: boolean; indent: integer);
const TEMPLATE = '%s : %s';
var
  line: string;
  newList: TStringList;
begin
  newList := TStringList.Create;
  try
    PrettyPrintJSON(JSONValue.JsonValue, newList, indent);
    line := format(TEMPLATE, [JSONValue.JsonString.ToString, Trim(newList.Text)]);
  finally
    newList.Free;
  end;

  line := StringOfChar(' ', indent * INDENT_SIZE) + line;
  if not last then
    line := line + ',';
  OutputStrings.add(line);
end;

procedure PrettyPrintArray(JSONValue: TJSONArray; OutputStrings: TStrings; last: boolean; indent: integer);
var i: integer;
begin
   OutputStrings.add(StringOfChar(' ', indent * INDENT_SIZE) + '[');
   for i := 0 to JSONValue.size - 1 do
      PrettyPrintJSON(JSONValue.Get(i), OutputStrings, indent + 1);
   OutputStrings.add(StringOfChar(' ', indent * INDENT_SIZE) + ']');
end;

procedure PrettyPrintJSON(JSONValue: TJSONValue; OutputStrings: TStrings; indent: integer = 0);
var
  i: integer;
begin
  if JSONValue is TJSONObject then
  begin
    OutputStrings.add(StringOfChar(' ', indent * INDENT_SIZE) + '{');
    for i := 0 to TJSONObject(JSONValue).size - 1 do
      PrettyPrintPair(TJSONObject(JSONValue).Get(i), OutputStrings, i = TJSONObject(JSONValue).size - 1, indent + 1);
    OutputStrings.add(StringOfChar(' ', indent * INDENT_SIZE) + '}');
  end
  else if JSONValue is TJSONArray then
    PrettyPrintArray(TJSONArray(JSONValue), OutputStrings, i = TJSONObject(JSONValue).size - 1, indent + 1)
  else OutputStrings.add(StringOfChar(' ', indent * INDENT_SIZE) + JSONValue.ToString);
end;

end.



回答3:


To augment the answer by Doggen and Wheeler, I replaced the PrettyPrintArray routine with the following replacement in order to make sure that array objects are separated by commas otherwise the prettyprint output is invalid json.

procedure PrettyPrintArray(JSONValue: TJSONArray; OutputStrings: TStrings; last:     boolean; indent: integer);
var i: integer;
begin
   OutputStrings.add(StringOfChar(' ', indent * INDENT_SIZE) + '[');
  for i := 0 to JSONValue.size - 1 do
      begin
      PrettyPrintJSON(JSONValue.Get(i), OutputStrings, indent + 1);
      if i < JSONValue.size - 1 then
         OutputStrings[OutputStrings.Count-1] := OutputStrings[OutputStrings.Count-1] + ',';
      end;
   OutputStrings.add(StringOfChar(' ', indent * INDENT_SIZE) + ']');
end;


来源:https://stackoverflow.com/questions/11797583/jsonvalue-to-indented-string

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!