修改SuperObject以不同格式/缩进JSON字符串?

3
在使用SuperObject库时,一个JSON对象目前会被缩进如下:
{
 "name": "value",
 "int_arr": [
  1,2,3],
 "obj_arr": [
  {
   "this": "that"
  },{
   "some": "thing"
  }],
 "another": 123
}

然而,这种缩进/格式并不像JSON所吹嘘的那样“用户友好”或“易读”。我知道在计算机语言中这并不重要,但我更喜欢按照以下方式进行格式化:

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

例如,使用JSONLint来验证/格式化JSON代码时,它会以更清晰的方式进行操作。
我该如何修改SuperObject库以不同的方式进行格式化?是否有特定的位置在库中定义这些格式化规则?或者我需要深入到代码的许多不同位置来进行更改?

我相信这是一个关于Henry Gourvest的问题... - Jerry Dodge
1
格式化是在 TSuperObject.Write 中完成的,其中 Indent = True。 - David A
@DavidA 非常感谢您指出这一点,帮助我解决了大部分问题。请看下面的答案。 - Jerry Dodge
@DavidHeffernan 抱歉,已完成。我意识到我问题中的代码都搞砸了。 - Jerry Dodge
1个回答

3

感谢David A的评论,实现这些更改非常简单(格式化源代码并理解库代码的工作原理之后)。所有格式都在TSuperObject.Write中实现,所有这样的更改都可以在此处进行。

我只遇到了一个问题,就是除对象外的其他类型的数组 - 值将移至下一行。但至少数组结尾和对象数组具有所需的换行和缩进。

以下是TSuperObject.Write的修改版本(为节省空间,大多数子程序未包含)。更改已加注释:

常量:

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

子程序:

  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;

过程体:

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;

那段代码将生成以下JSON数据:
{
  "name": "value",
  "int_arr": [
    1,2,3
  ],
  "obj_arr": [
    {
      "this": "that"
    },
    {
      "some": "thing"
    }
  ],
  "another": 123
} 

2
仅通过阅读您发布的源代码,您是否将TOK_SP更改为#32#32并添加了Append(TOK_SP,2)。最后一个值是标记的长度(TOK_CRLF->2,TOK_NULL->4)。 - Sir Rufo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接