Reputation: 27266
While using the SuperObject
library, a single JSON object currently gets indented like so:
{
"name": "value",
"int_arr": [
1,2,3],
"obj_arr": [
{
"this": "that"
},{
"some": "thing"
}],
"another": 123
}
However, this indentation/formatting is not the same "user-friendly" or "human-readable" as JSON is all hyped up to be. I understand in computer language, this doesn't necessarily matter, but I'd like to format it like so instead:
{
"name": "value",
"int_arr": [1,2,3],
"obj_arr": [
{
"this": "that"
},
{
"some": "thing"
}
],
"another": 123
}
For example, when using JSONLint to validate/format JSON code, it does so in a much cleaner manner.
How can I go about modifying the SuperObject
library to format it differently? Is there a particular place in the library which defines these formatting rules? Or would I have to dig into the code in many different places to change this?
Upvotes: 3
Views: 1008
Reputation: 27266
Thanks to the comment by David A
, it was rather simple to implement these changes (after formatting the source and understanding how the library's code works). All the formatting is implemented in TSuperObject.Write
, and all of such changes can be made here.
There was only one issue I could not figure out, which was arrays of types other than objects - the values will go to the next line. But at least array endings and arrays of objects have line breaks and indentation as desired.
Here's the modified version of TSuperObject.Write
below (most subroutines not included to save space). Changes commented:
Constant:
const
TOK_SP: PSOChar = #32#32; //<-- added another #32
Subroutine:
procedure _indent(I: shortint; r: boolean);
begin
Inc(level, I);
if r then
with writer do
begin
{$IFDEF MSWINDOWS}
Append(TOK_CRLF, 2);
{$ELSE}
Append(TOK_LF, 1);
{$ENDIF}
for I := 0 to level - 1 do
Append(TOK_SP, 2); //<-- changed 1 to 2
end;
end;
Procedure body:
begin
if FProcessing then
begin
Result := writer.Append(TOK_NULL, 4);
Exit;
end;
FProcessing := true;
with writer do
try
case FDataType of
stObject:
if FO.c_object.FCount > 0 then
begin
k := 0;
Append(TOK_CBL, 1);
if indent then
_indent(1, false);
if ObjectFindFirst(Self, iter) then
repeat
{$IFDEF SUPER_METHOD}
if (iter.val = nil) or not ObjectIsType(iter.val, stMethod) then
begin
{$ENDIF}
if (iter.val = nil) or (not iter.val.Processing) then
begin
if (k <> 0) then
Append(TOK_COM, 1);
if indent then
_indent(0, true);
Append(TOK_DQT, 1);
if escape then
DoEscape(PSOChar(iter.key), Length(iter.key))
else
DoMinimalEscape(PSOChar(iter.key), Length(iter.key));
if indent then
Append(ENDSTR_A, 3)
else
Append(ENDSTR_B, 2);
if (iter.val = nil) then
Append(TOK_NULL, 4)
else
iter.val.Write(writer, indent, escape, level);
Inc(k);
end;
{$IFDEF SUPER_METHOD}
end;
{$ENDIF}
until not ObjectFindNext(iter);
ObjectFindClose(iter);
if indent then
_indent(-1, true);
Result := Append(TOK_CBR, 1);
end
else
Result := Append(TOK_OBJ, 2);
stBoolean:
begin
if (FO.c_boolean) then
Result := Append(TOK_TRUE, 4)
else
Result := Append(TOK_FALSE, 5);
end;
stInt:
begin
str(FO.c_int, st);
Result := Append(PSOChar(SOString(st)));
end;
stDouble:
Result := Append(PSOChar(SOString(gcvt(FO.c_double, 15, fbuffer))));
stCurrency:
begin
Result := Append(PSOChar(CurrToStr(FO.c_currency)));
end;
stString:
begin
Append(TOK_DQT, 1);
if escape then
DoEscape(PSOChar(FOString), Length(FOString))
else
DoMinimalEscape(PSOChar(FOString), Length(FOString));
Append(TOK_DQT, 1);
Result := 0;
end;
stArray:
if FO.c_array.FLength > 0 then
begin
Append(TOK_ARL, 1);
if indent then
_indent(1, true);
k := 0;
j := 0;
while k < FO.c_array.FLength do
begin
val := FO.c_array.GetO(k);
{$IFDEF SUPER_METHOD}
if not ObjectIsType(val, stMethod) then
begin
{$ENDIF}
if (val = nil) or (not val.Processing) then
begin
if (j <> 0) then begin
Append(TOK_COM, 1);
if ObjectIsType(val, stObject) then begin //
if indent then //<-- create line break after object array items
_indent(0, true); //
end; //
end;
if (val = nil) then
Append(TOK_NULL, 4)
else
val.Write(writer, indent, escape, level);
Inc(j);
end;
{$IFDEF SUPER_METHOD}
end;
{$ENDIF}
Inc(k);
end;
if indent then
_indent(-1, true); //<-- changed "false" to "true" to create line break at end of array
Result := Append(TOK_ARR, 1);
end
else
Result := Append(TOK_ARRAY, 2);
stNull:
Result := Append(TOK_NULL, 4);
else
Result := 0;
end;
finally
FProcessing := false;
end;
end;
That code would produce JSON data like so:
{
"name": "value",
"int_arr": [
1,2,3
],
"obj_arr": [
{
"this": "that"
},
{
"some": "thing"
}
],
"another": 123
}
Upvotes: 3