创建树结构的JSON

创建树结构的JSON,json,delphi,recursion,Json,Delphi,Recursion,我有一个对象列表,类型为TDepartment,如下所示 TDepartment = class ID : Integer; Name : string; ParentDepartmentID : Integer; end; 我需要创建一个TJSONObject,其中包含一个部门数组,也可以包含一个部门数组。因此,这个问题的深度不得而知 我现在的处境对我来说毫无意义,但我希望生成的JSON如下所示: "department_id": "5", "department

我有一个对象列表,类型为TDepartment,如下所示

TDepartment = class
  ID : Integer;
  Name : string;
  ParentDepartmentID : Integer;
end;
我需要创建一个TJSONObject,其中包含一个部门数组,也可以包含一个部门数组。因此,这个问题的深度不得而知

我现在的处境对我来说毫无意义,但我希望生成的JSON如下所示:

    "department_id": "5",
    "department_name": "100",
    "parent_dept_id": "",
    "subdepartments": [{
        "department_id": "8",
        "department_name": "300",
        "parent_dept_id": "5",
        "subdepartments": [{
            "department_id": "1",
            "department_name": "310",
            "parent_dept_id": "8",
            "subdepartments": []
unit Unit1;

interface

uses
  System.Generics.Collections;

type
  TDepartment = class
    ID : Integer;
    Name : string;
    ParentDepartmentID : Integer;
  end;

  TDepartmentStructure = class
    ID : Integer;
    Name : string;
    ParentDepartmentID : Integer;
    SubDepartments: TList< TDepartmentStructure >;
    constructor Create( const pBasedOn : TDepartment );
  end;

var
  Department : TObjectList<TDepartment>;

function CopyStructure( pDepartment : TList<TDepartment> ) : TDepartmentStructure; // returns root

implementation

var
  DepartmentStructure : TObjectList<TDepartmentStructure>;

function CopyStructure( pDepartment : TList<TDepartment> ) : TDepartmentStructure;
var
  i, j: Integer;
begin
  // stage one - copy everything
  for i := 0 to pDepartment.Count - 1 do
  begin
    DepartmentStructure.Add( TDepartmentStructure.Create( pDepartment[ i ] ));
  end;
  // now go through and build structure
  Result := nil;
  for i := 0 to DepartmentStructure.Count - 1 do
  begin
    if DepartmentStructure[ i ].ID = 0 then
    begin
      // root
      Result := DepartmentStructure[ i ];
    end
    else
    begin
      for j := 0 to DepartmentStructure.Count - 1 do
      begin
        if DepartmentStructure[ i ].ParentDepartmentID = DepartmentStructure[ j ].ID then
        begin
          DepartmentStructure[ j ].SubDepartments.Add( DepartmentStructure[ i ] );
          break;
        end;
      end;
    end;
  end;
end;

{ TDepartmentStructure }

constructor TDepartmentStructure.Create(const pBasedOn: TDepartment);
begin
  inherited Create;
  ID := pBasedOn.ID;
  Name := pBasedOn.Name;
  ParentDepartmentID := pBasedOn.ParentDepartmentID;
  SubDepartments:= TObjectList< TDepartmentStructure >.Create( FALSE ); // we do NOT own these objects!

end;

initialization
  DepartmentStructure := TObjectList<TDepartmentStructure>.Create( TRUE );

finalization
  DepartmentStructure.Free;

end.
请记住,每个级别都有未知数量的兄弟姐妹和孩子。
我想我需要编写一个递归过程,但我无法将其可视化。

首先,您可能希望
TDepartment
的声明与您描述的嵌套结构相匹配:

TDepartment = class
  ID : Integer;
  Name : string;
  ParentDepartmentID : Integer;
  SubDepartments: array of TDepartment;
end;
为了将其序列化,我建议使用SuperObject库而不是内置的JSON类:

function TDepartment.Serialize: ISuperObject;
  var Context: TSuperRttiContext;
begin
  Context := TSuperRttiContext.Create;
  try
    Result := Context.AsJson<TDepartment>(self);
  finally
    Context.Free;
  end;
end;

我将创建一个平行的树结构,保持原始结构不变。您当前的结构与您需要的相反,因此您可以扫描当前对象并将它们放置在树中。但在不了解当前结构的情况下,很难给出示例代码,但假设所有部门都存在于某种列表中,(我们称之为“部门”),并且“根”部门的父部门ID为零,则会出现如下情况:

    "department_id": "5",
    "department_name": "100",
    "parent_dept_id": "",
    "subdepartments": [{
        "department_id": "8",
        "department_name": "300",
        "parent_dept_id": "5",
        "subdepartments": [{
            "department_id": "1",
            "department_name": "310",
            "parent_dept_id": "8",
            "subdepartments": []
unit Unit1;

interface

uses
  System.Generics.Collections;

type
  TDepartment = class
    ID : Integer;
    Name : string;
    ParentDepartmentID : Integer;
  end;

  TDepartmentStructure = class
    ID : Integer;
    Name : string;
    ParentDepartmentID : Integer;
    SubDepartments: TList< TDepartmentStructure >;
    constructor Create( const pBasedOn : TDepartment );
  end;

var
  Department : TObjectList<TDepartment>;

function CopyStructure( pDepartment : TList<TDepartment> ) : TDepartmentStructure; // returns root

implementation

var
  DepartmentStructure : TObjectList<TDepartmentStructure>;

function CopyStructure( pDepartment : TList<TDepartment> ) : TDepartmentStructure;
var
  i, j: Integer;
begin
  // stage one - copy everything
  for i := 0 to pDepartment.Count - 1 do
  begin
    DepartmentStructure.Add( TDepartmentStructure.Create( pDepartment[ i ] ));
  end;
  // now go through and build structure
  Result := nil;
  for i := 0 to DepartmentStructure.Count - 1 do
  begin
    if DepartmentStructure[ i ].ID = 0 then
    begin
      // root
      Result := DepartmentStructure[ i ];
    end
    else
    begin
      for j := 0 to DepartmentStructure.Count - 1 do
      begin
        if DepartmentStructure[ i ].ParentDepartmentID = DepartmentStructure[ j ].ID then
        begin
          DepartmentStructure[ j ].SubDepartments.Add( DepartmentStructure[ i ] );
          break;
        end;
      end;
    end;
  end;
end;

{ TDepartmentStructure }

constructor TDepartmentStructure.Create(const pBasedOn: TDepartment);
begin
  inherited Create;
  ID := pBasedOn.ID;
  Name := pBasedOn.Name;
  ParentDepartmentID := pBasedOn.ParentDepartmentID;
  SubDepartments:= TObjectList< TDepartmentStructure >.Create( FALSE ); // we do NOT own these objects!

end;

initialization
  DepartmentStructure := TObjectList<TDepartmentStructure>.Create( TRUE );

finalization
  DepartmentStructure.Free;

end.
单元1;
接口
使用
系统、泛型、集合;
类型
t部门=班级
ID:整数;
名称:字符串;
ParentDepartmentID:整数;
结束;
TDepartmentStructure=class
ID:整数;
名称:字符串;
ParentDepartmentID:整数;
子部门:TList;
构造函数创建(constpbasedon:TDepartment);
结束;
变量
部门:TObjectList;
函数CopyStructure(pDepartment:TList):TDepartmentStructure;//返回根
实施
变量
部门结构:TObjectList;
功能CopyStructure(pDepartment:TList):TDepartmentStructure;
变量
i、 j:整数;
开始
//第一阶段-复制所有内容
对于i:=0到pDepartment.Count-1 do
开始
DepartmentStructure.Add(TDepartmentStructure.Create(pDepartment[i]);
结束;
//现在完成并构建结构
结果:=无;
对于i:=0到DepartmentStructure.Count-1 do
开始
如果DepartmentStructure[i].ID=0,则
开始
//根
结果:=部门结构[i];
结束
其他的
开始
对于j:=0到DepartmentStructure.Count-1 do
开始
如果DepartmentStructure[i].ParentDepartmentID=DepartmentStructure[j].ID,则
开始
DepartmentStructure[j].SubDepartments.Add(DepartmentStructure[i]);
打破
结束;
结束;
结束;
结束;
结束;
{TDepartmentStructure}
构造函数TDepartmentStructure.Create(constpbasedon:TDepartment);
开始
继承创造;
ID:=pBasedOn.ID;
名称:=pBasedOn.Name;
ParentDepartmentID:=pBasedOn.ParentDepartmentID;
子部门:=TObjectList.Create(FALSE);//我们不拥有这些物品!
结束;
初始化
DepartmentStructure:=TObjectList.Create(TRUE);
定稿
部门结构。免费;
结束。

请注意,这仅用于说明目的。你可能不会创建和破坏我拥有的结构。一旦有了这个结构,您就可以使用当前的例程创建JSON记录了。

我简化了代码,只是为了举个例子,实际上TDepartments有数百个属性和字段,它是旧框架中百万行以上代码库的一部分,因此JSON和TDepartment确实匹配。这也是我需要使用内置JSON类的原因,因为它们在整个应用程序中都会使用。您想将TDepartment的所有字段序列化为JSON,还是仅序列化示例中的字段?仅序列化示例中的字段:),但值得注意的是,父级与其子级之间的唯一关系是“父部门id”,而且部门本身没有“子部门”属性,这是一种非常糟糕的父子关系建模方法。。。我不相信您可以轻松地将类序列化到TJSONObject,但是如果您只需要几个字段,那么您可能希望以自己的方式实现。请看一下对我答案的编辑。@MattBaech SuperObject确实更易于使用,测试也更好。您可能可以创建它,然后将其导出为JSON字符串,然后从该字符串加载TJSONObject。您可以为TDepartment注册自定义序列化程序,然后使用SuperObject内置的typecast进行工作