{格式化 JSON 单元
}
unit uFomat_JSON;

interface

uses
  system.JSON, System.SysUtils, System.Variants, System.Classes;

const
  Level_indent = 2;


//格式化 JSON 字符串
// JSONStr : 表示需要格式化的 JSON字符串
// lv : 表示缩进层级
function JSON_Format(JSONStr: string; lv: Word = 0): string;


//格式化数组, 缩进
function JSON_Fromat_Array(ja: TJSONArray; lv: word = 0): string;

//跨过的indent
function LI(lv: Word): string;

implementation

//格式化 JSON 字符串
// JSONStr : 表示需要格式化的 JSON字符串
// Left_Space : 表示左边统一留多少个空格
// Level_index ：表示每级缩进多个个空格
function JSON_Format(JSONStr: string; lv: Word = 0): string;
var
  S: string;
  jo: TJSONObject;
  jo1: TJSONObject;
  jp: TJSONPair;
  js: TJSONString;
  jn: TJSONNumber;
  jb: TJSONBool;
  ja: TJSONArray;
  jpe: TJSONObject.TEnumerator;
begin
  //1. 解析 JSONStr
  jo := TJSONObject.ParseJSONValue(JSONStr) as TJSONObject;
  if jo = nil then
    Exit(JSONStr);

  Result := '{' + #13#10;
  try
    jpe := jo.GetEnumerator;
    if jpe = nil then
      Exit(JSONStr);

    while jpe.MoveNext do
    begin
      jp := jpe.Current;
      if jp.JsonValue.TryGetValue(jo1) then
      begin
        Result := Result + LI(lv + 1) + '"' + jp.JsonString.Value + '":'#13#10;
        Result := Result + LI(lv + 1) + JSON_Format(jo1.ToJSON, lv + 2);
        Continue;
      end
      else if jp.JsonValue.TryGetValue(jn) then   //数字
        Result := Result + LI(lv + 1) + '"' + jp.JsonString.Value + '": ' + jn.Value + ','#13#10
      else if jp.JsonValue.TryGetValue(jb) then  //Boolean
        Result := Result + LI(lv + 1) + '"' + jp.JsonString.Value + '": ' + jb.Value + ','#13#10
      else if jp.JsonValue.TryGetValue(ja) then   //字符串
      begin
        Result := Result + LI(lv + 1) + '"' + jp.JsonString.Value + '": '#13#10;
        Result := Result + LI(lv + 1) + JSON_Fromat_Array(ja, lv + 1);
      end
      else if jp.JsonValue.TryGetValue(js) then   //字符串
        Result := Result + LI(lv + 1) + '"' + jp.JsonString.Value + '": "' + js.Value + '",'#13#10
    end;
    //去掉最后一行的 ,
    S := Result.Substring(Length(Result) - 3, 3);
    if S = ','#13#10 then
      Result := Result.Substring(0, Length(Result) - 3) + #13#10;
    //最后结果的 }
    if lv > 0 then
    begin
      lv := lv - 1;
      Result := Result + LI(lv) + '},'#13#10;
    end
    else
      Result := Result + LI(0) + '}'#13#10;
  finally
    if jo <> nil then
      jo.Free;
    if jpe <> nil then
      jpe.Free;
  end;
end;


//格式化数组, 缩进
function JSON_Fromat_Array(ja: TJSONArray; lv: word = 0): string;
var
  jae: TJSONArray.TEnumerator;
  jv: TJSONValue;
  js: TJSONString;
  jn: TJSONNumber;
  jb: TJSONBool;
  jo: TJSONObject;
  ja1: TJSONArray;
  S: string;
begin
  //
  Result := '['#13#10;
  jae := ja.GetEnumerator;
  if jae = nil then
    Exit('');

  while jae.MoveNext do
  begin
    jv := jae.Current;
      //进行数据处理
    if jv.TryGetValue(jn) then   //Number
      Result := Result + LI(lv + 1) + jn.Value + ','#13#10
    else if jv.TryGetValue(jb) then  //Boolean
      Result := Result + LI(lv + 1) + jb.Value + ','#13#10
    else if jv.TryGetValue(jo) then  //JSONObject
    begin
      Result := Result + LI(lv + 1) + JSON_Format(jo.ToString, lv + 2);
    end
    else if jv.TryGetValue(ja1) then  //JSONArray
      Result := Result + LI(lv + 1) + JSON_Fromat_Array(ja1, lv + 1)
    else if jv.TryGetValue(js) then  //string
      Result := Result + LI(lv + 1) + '"' + js.Value + '",'#13#10;
  end;
  //去掉最后一行的 ,
  S := Result.Substring(Length(Result) - 3, 3);
  if S = ','#13#10 then
    Result := Result.Substring(0, Length(Result) - 3) + #13#10;
  Result := Result + LI(lv) + '],'#13#10;

  if jae <> nil then
    jae.Free;
end;


//跨过的indent
function LI(lv: Word): string;
begin
  Result := StringOfChar(' ', lv * Level_indent);
end;

end.

