如何在 Delphi XE2 中解析嵌套的 JSON 对象?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10808912/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 18:21:26  来源:igfitidea点击:

How to parse nested JSON object in Delphi XE2?

jsondelphinesteddelphi-xe2

提问by Bogdan Botezatu

I'm new to JSON and I have this project on my hands that require me to parse a JSON and display some of its contents in a ListView. The problem is that the documentation I've read by now dealt with JSON objects containing JSON arrays, while my case involves dealing with nested objects. To cut the story short, here's the summary: I'm using Delphi XE2 with DBXJSON. I post some values to a server and it replies with a JSON object that looks like that:

我是 JSON 的新手,我手头有这个项目,需要我解析 JSON 并在 ListView 中显示它的一些内容。问题是我现在阅读的文档处理包含 JSON 数组的 JSON 对象,而我的案例涉及处理嵌套对象。简而言之,总结如下:我将 Delphi XE2 与 DBXJSON 结合使用。我将一些值发布到服务器,它回复一个 JSON 对象,如下所示:

    {
    "products": {
        "Men's Sneakers": {
            "instock": false,
            "size": "423",
            "manufacturer": "Adidas",
            "lastcheck": "20120529"
        },
        "Purse": {
            "instock": true,
            "size": "not applicable",
            "manufacturer": "Prada",
            "lastcheck": "20120528"
        },
        "Men's Hood": {
            "instock": false,
            "size": "M",
            "manufacturer": "Generic",
            "lastcheck": "20120529"
       }
    },
   "total": 41,
   "available": 30
}

What I wanted to achieve was to have each item (i.e. Purse) parsed and added as caption in a listview, along with one subitem (manufacturer). I created a procedure that takes the JSON string as argument, created the JSON object, but I don't know how to parse the nested objects any further.

我想要实现的是将每个项目(即钱包)解析并添加为列表视图中的标题,以及一个子项目(制造商)。我创建了一个将 JSON 字符串作为参数的过程,创建了 JSON 对象,但我不知道如何进一步解析嵌套对象。

procedure TForm1.ParseString(const AString: string);
var
  json          : TJSONObject;
  jPair         : TJSONPair;
  jValue        : TJSONValue;
  jcValue       : TJSONValue;
  l,i           : Integer;
begin
    json    := TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(AString),0) as TJSONObject;
  try
    //get the pair to evaluate in this case the index is 1
    jPair   := json.Get(1); 
        {further process the nested objects and adding them to the listview}
  finally
     json.Free;
  end;
end;

Any suggestions would be highly appreciated. Lost quite some time trying to get the ins and outs of JSON in Delphi with no avail.

任何建议将不胜感激。花了很多时间试图在 Delphi 中了解 JSON 的来龙去脉,但无济于事。

Thanks, sphynx

谢谢,斯芬克斯

回答by RRUZ

Try this sample

试试这个样本

{$APPTYPE CONSOLE}

{$R *.res}

uses
  DBXJSON,
  System.SysUtils;


Const
StrJson=
'{'+
'    "products": {'+
'        "Men''s Sneakers": {'+
'            "instock": false,'+
'            "size": "423",'+
'            "manufacturer": "Adidas",'+
'            "lastcheck": "20120529"'+
'        },'+
'        "Purse": {'+
'            "instock": true,'+
'            "size": "not applicable",'+
'            "manufacturer": "Prada",'+
'            "lastcheck": "20120528"'+
'        },'+
'        "Men''s Hood": {'+
'            "instock": false,'+
'            "size": "M",'+
'            "manufacturer": "Generic",'+
'            "lastcheck": "20120529"'+
'        }'+
'    },'+
'    "total": 41,'+
'    "available": 30'+
'}';

procedure ParseJson;
var
  LJsonObj  : TJSONObject;
  LJPair    : TJSONPair;
  LProducts : TJSONValue;
  LProduct  : TJSONValue;
  LItem     : TJSONValue;
  LIndex    : Integer;
  LSize     : Integer;
begin
    LJsonObj    := TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(StrJson),0) as TJSONObject;
  try
     LProducts:=LJsonObj.Get('products').JsonValue;
     LSize:=TJSONArray(LProducts).Size;
     for LIndex:=0 to LSize-1 do
     begin
      LProduct := TJSONArray(LProducts).Get(LIndex);
      LJPair   := TJSONPair(LProduct);
      Writeln(Format('Product Name %s',[LJPair.JsonString.Value]));
        for LItem in TJSONArray(LJPair.JsonValue) do
        begin
           if TJSONPair(LItem).JsonValue is TJSONFalse then
            Writeln(Format('  %s : %s',[TJSONPair(LItem).JsonString.Value, 'false']))
           else
           if TJSONPair(LItem).JsonValue is TJSONTrue then
            Writeln(Format('  %s : %s',[TJSONPair(LItem).JsonString.Value, 'true']))
           else
            Writeln(Format('  %s : %s',[TJSONPair(LItem).JsonString.Value, TJSONPair(LItem).JsonValue.Value]));
        end;
     end;
  finally
     LJsonObj.Free;
  end;
end;

begin
  try
    ParseJson;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.

This will return

这将返回

Product Name Men's Sneakers
  instock : false
  size : 423
  manufacturer : Adidas
  lastcheck : 20120529
Product Name Purse
  instock : true
  size : not applicable
  manufacturer : Prada
  lastcheck : 20120528
Product Name Men's Hood
  instock : false
  size : M
  manufacturer : Generic
  lastcheck : 20120529

回答by mgibsonbr

This sitedescribes the type TJSONValuein more detail. If your data is an object, it will have the type TJSONObject, so check its API to see how to proceed.

该站点TJSONValue更详细地描述了该类型。如果您的数据是一个对象,它将具有 type TJSONObject,因此请检查其 API 以了解如何继续。

I believe the first thing you need it to iterate over its pairs (use GetEnumeratorif you don't know the key names, otherwise just use the overloaded Get- passing a string instead of a number). For each pair, the key will be a simple string (type TJSONString) and the value may be any TJSONValue. Repeat until you reach the leaves.

我相信您首先需要它遍历其对(GetEnumerator如果您不知道键名,则使用它,否则只需使用重载Get- 传递一个字符串而不是数字)。对于每一对,键是一个简单的字符串(类型TJSONString),值可以是 any TJSONValue。重复直到你到达叶子。

Example:

例子:

products   := jPair.Get('products');
purse      := products.GetJsonValue().Get('Purse');
purseManuf := purse.GetJsonValue().Get('manufacturer');
...

Or if you don't know what the products are:

或者,如果您不知道产品是什么:

products   := jPair.Get('products');
for prodPair in products.GetEnumerator() do
begin
    prodName := prodPair.GetJsonString();
    prodObj  := prodPair.GetJsonValue();
    ...

回答by Please_Dont_Bully_Me_SO_Lords

This blog postshows a very modern and simple way to convert JSON:

这篇博文展示了一种非常现代且简单的 JSON 转换方法:

uses REST.JSON; // Also new System.JSON
procedure TForm1.Button1Click(Sender: TObject);

var
  Foo: TFoo;

begin
  Foo := TFoo.Create;

  try
    Foo.Foo := 'Hello World';
    Foo.Fee := 42;
    Memo1.Lines.Text := TJson.ObjectToJsonString(Foo);
  finally
    Foo.Free;
  end;

  Foo := TJson.JsonToObject<TFoo>(Memo1.Lines.Text);

  try
    Foo.Fee := 100;
    Memo1.Lines.Add(TJson.ObjectToJsonString(Foo));
  finally
    Foo.Free;
  end;
end;