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;