0

我正在使用 Delphi XE2,我有这个 json 结构要创建:

[
    {
        "Email": "laura@yyyy.com",
        "MobileNumber": "",
        "MobilePrefix": "",
        "Name": "Laura",
        "Fields": [
            {
                "Description": "nominativo",
                "Id": "1",
                "Value": "Laura"
            },
            {
                "Description": "societa",
                "Id": "2",
                "Value": ""
            },
            {
                "Description": "idcontatto",
                "Id": "3",
                "Value": "0"
            }
        ]
    },
    {
        "Email": "paolo@xxxx.com",
        "MobileNumber": "",
        "MobilePrefix": "",
        "Name": "Paolo",
        "Fields": [
            {
                "Description": "nominativo",
                "Id": "1",
                "Value": "Paolo"
            },
            {
                "Description": "societa",
                "Id": "2",
                "Value": ""
            },
            {
                "Description": "idcontatto",
                "Id": "3",
                "Value": "1"
            }
        ]
    }
]

我用超级对象做了几次测试,但还没有得到正确的结果,因为我得到的数组的第一个元素等于第二个。我的困难在于迭代和优化。这是我正在处理的代码:。

json := TSuperObject.Create;    
jsonArray:= TSuperObject.Create(stArray);

json.S['Email'] := 'laura@yyyy.com';    
json.S['MobileNumber'] := '';    
json.S['MobilePrefix'] := '';    
json.S['Name'] := 'Laura';    
json['Fields'] := SA([]);    
json_Fields:=SO;    
json_Fields.S['Description']:='nominativo';    
json_Fields.S['Id']:='1';    
json_Fields.S['Value']:='Laura';    
json.A['Fields'].Add(json_Fields);    
json_Fields:=SO;    
json_Fields.S['Description']:='societa';    
json_Fields.S['Id']:='2';    
json_Fields.S['Value']:='';    
json.A['Fields'].Add(json_Fields);    
//......other fields    
JsonArray.AsArray.Add(json);

json.S['Email'] := 'paolo@xxxx.com';    
json.S['MobileNumber'] := '';    
json.S['MobilePrefix'] := '';    
json.S['Name'] := 'Paolo';    
json['Fields'] := SA([]);    
json_Fields:=SO;    
json_Fields.S['Description']:='nominativo';    
json_Fields.S['Id']:='1';    
json_Fields.S['Value']:='Paolo';    
json.A['Fields'].Add(json_Fields);    
json_Fields:=SO;    
json_Fields.S['Description']:='societa';    
json_Fields.S['Id']:='2';    
json_Fields.S['Value']:='';    
json.A['Fields'].Add(json_Fields);    
//......other fields    
JsonArray.AsArray.Add(json);

jsonArray.SaveTo('json_mu.txt');    
4

2 回答 2

2

您可以使用我们的基于记录的 JSON 序列化

首先定义一条记录,包含预期的数据项和相应的动态数组:

type
  TMyRecord: record
    Name: string;
    Email: string;
    MobileNumber: string;
    MobilePrefix: string;
    Fields: array of record
      Id: integer;
      Description: string;
      Value: string;
    end;
  end;
  TMyRecordDynArray = array of TMyRecord;

然后你注册记录内容:

const // text description of the record layout
  __TMyRecord = 'Name,Email,MobileNumber,MobilePrefix string '+
    'Fields[Id integer Description,Value string]';

  ...

  TTextWriter.RegisterCustomJSONSerializerFromText(
    TypeInfo(TMyRecord),__TMyRecord);

您可以从/到 JSON 加载或保存数据:

var values: TMyRecordDynArray;
    i: integer;

  DynArrayLoadJSON(values,pointer(StringToUTF8(text)),TypeInfo(TMyRecordDynArray));
  for i := 0 to high(values) do
    writeln('name: ',values[i].Name,' mobile: ',values[i].MobilePrefix,' fields count:',length(values[i].Fields));
  DynArraySaveJSON(values,TypeInfo(TMyRecordDynArray));

这个 JSON 序列化程序将使用比替代方案更少的内存,可能会更快,并且您可以在编译时检查属性名称。

这是从 Delphi 6 到 XE5 可用的。

编辑:

例如,要填充数组:

var R: TMyRecordDynArray;

SetLength(R,2);
with R[0] do begin
  Email := 'laura@yyyy.com';
  Name := 'Laura';
  Setlength(Fields,3);
  Fields[0].Description := 'nominativo';
  Fields[0].Id := 1;
  Fields[0].Value := 'Laura';
  Fields[1].Description := 'societa';
  Fields[1].Id := 2;
  Fields[2].Description := 'idcontatto';
  Fields[2].Id := 3;
  Fields[2].Value := '0';
end;
with R[1] do begin
  Email := 'paolo@xxxx.com';
  Name := 'Paolo';
  Setlength(Fields,3);
  Fields[0].Description := 'nominativo';
  Fields[0].Id := 1;
  Fields[0].Value := 'Paolo';
  Fields[1].Description := 'societa';
  Fields[1].Id := 2;
  Fields[2].Description := 'idcontatto';
  Fields[2].Id := 3;
  Fields[2].Value := '1';
end;

json := DynArraySaveJSON(R,TypeInfo(TMyRecordDynArray));

如果您不喜欢该with声明,则可以在R[0].任何地方添加。我怀疑不是这里的重点。

我希望它能够清楚地显示使用编译时结构而不是定义为文本的后期绑定属性的好处(因为您正在使用 SuperObject):您不会期望在运行时出现任何问题,关于属性名称或一般逻辑。

如果您编写json_Fields.S['DescriptioM']:='nominativo',您将不会在 IDE 中看到任何错误,而Fields[0].DescriptioM := 'nominativo'不会编译。

如果要更改属性名称,可以在 IDE 中对其进行重构,而不会忘记代码中的某个位置——它不会编译。

如果您的业务代码使用高级 Delphi 结构,您将需要使用大多数备用库手动编写一些容易出错的代码来将这些高级值转换为 JSON 或从 JSON 转换。而使用这样的解决方案,您可以定义自己的值对象record,甚至可以在类型定义中添加一些方法,并直接在您的业务代码中使用它,而无需担心 JSON 持久层的实现细节。简而言之:您想在业务代码中添加对 JSON 库的依赖吗?听起来像是打破了我们在定义领域驱动设计代码时试图遵循的一些原则。

还要与您在答案中添加的代码进行比较,了解代码的可读性和可维护性。

并且默认情况下使用 '' 初始化所有未定义的字符串字段的好处(与任何动态数组一样)。

编辑2:

正如Jan 在他自己的答案中所写,您可以使用 SuperObject 直接序列化记录和动态数组,就像我们的类一样。因此,如果您想使用 SuperObject,我的建议是使用此功能,并使用 Delphi 高级类型。请注意,SuperObject 序列化可能会比我们单元中的序列化要慢,并且不适用于旧版本的 Delphi(而我们的单元适用于 Delphi 6/7,例如)。

于 2014-02-20T16:04:48.347 回答
1

使用超级对象:

定义要使用的 Delphi 数据结构,而不是手动构建 JSON 结构,然后使用 ToJSON 将 Delphi 对象转换为 JSON 结构:

Uses SuperObject;

type
   FieldRec = record
      ID: Integer;
      Description,
      Value: String;
   end;
   FieldArr = Array of FieldRec;
   BaseRec = record
      Fields: FieldArr;
   end;
   BaseArr = Array of BaseRec;

   OutputObject = class
      OutputData: BaseArr;
   end;

procedure TFrmAnotherJSONExample.FormShow(Sender: TObject);
var
   sObj: ISuperObject;
   lFieldArr: FieldArr;
   lBaseArr : BaseArr;
   lOutputObject: OutputObject;
begin
  SetLength(lBaseArr,2);
  SetLength(lFieldArr,3);
  for i := 0 to 2 do
  begin
     lFieldArr[i].ID := 10*i;
     lFieldArr[i].Description := 'Description' + IntToStr(lFieldArr[0].ID);
     lFieldArr[i].Value := 'Name' + IntToStr(lFieldArr[0].ID);
  end;
  lBaseArr[0].Fields := lFieldArr;
  for i := 0 to 2 do
  begin
     lFieldArr[i].ID := 100*i;
     lFieldArr[i].Description := 'Description' + IntToStr(lFieldArr[0].ID);
     lFieldArr[i].Value := 'Name' + IntToStr(lFieldArr[0].ID);
  end;
  lBaseArr[1].Fields := lFieldArr;
  lOutputObject := OutputObject.Create;
  lOutputObject.OutputData := lBaseArr;
  sObj := lOutputObject.ToJSON;
  lOutputObject.Free;
  Memo1.Lines.Add(sObj.AsJSON(true));
end;

上述输出:

{
 "OutputData": [
  {
   "Fields": [
    {
     "Description": "Description0",
     "ID": 0,
     "Value": "Name0"
    },{
     "Description": "Description0",
     "ID": 100,
     "Value": "Name0"
    },{
     "Description": "Description0",
     "ID": 200,
     "Value": "Name0"
    }]
  },
 {
   "Fields": [
    {
     "Description": "Description0",
     "ID": 0,
     "Value": "Name0"
    },{
     "Description": "Description0",
     "ID": 100,
     "Value": "Name0"
    },{
     "Description": "Description0",
     "ID": 200,
     "Value": "Name0"
    }]
  }]
}

这样你就可以得到命名数组,我假设这很好(我会推荐它)。
此外,它具有定义 JSON 对象的外部 {}。

补充:发布后我发现我忘记填写电子邮件手机号码等字段,但现在这很简单,我把它作为练习留给读者;-)

于 2014-02-21T15:51:21.860 回答