Modify SuperObject to format / indent JSON string differently?

When using the library, a SuperObject

single JSON object is currently indented like this:

{
 "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" since the JSON is all bloated. I understand in computer language, this is not necessarily important, but I would like to format it like this:

{
  "name": "value",
  "int_arr": [1,2,3],
  "obj_arr": [
    {
      "this": "that"
    },
    {
      "some": "thing"
    }
  ],
  "another": 123
} 

      

For example, when using JSONLint to validate / format your JSON code, it does it in a much cleaner way.

How can I change the library SuperObject

to format it differently? Is there a place in the library that defines these formatting rules? Or will I have to dig through the code in many different places to change this?

+3


source to share


1 answer


Thanks to the comment, David A

it was quite easy to implement these changes (after formatting the source and understanding how the library code works). All formatting is implemented in TSuperObject.Write

, and all such changes can be made here.

There was only one problem I couldn't figure out which was an array of non-object types - the values ​​would go to the next line. But at least massive endings and object arrays have line breaks and indentation as desired.

Here's a modified version TSuperObject.Write

below (most routines are not included to save space). Changes are commented:

Constant:

const
  TOK_SP: PSOChar = #32#32; //<-- added another #32

      

subroutines:



  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;

      

This code will generate JSON data like this:

{
  "name": "value",
  "int_arr": [
    1,2,3
  ],
  "obj_arr": [
    {
      "this": "that"
    },
    {
      "some": "thing"
    }
  ],
  "another": 123
} 

      

+3


source







All Articles