{格式化 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.