delphi 测试嵌套JSON元素是否存在(使用超级对象)

mepcadol  于 2023-01-08  发布在  其他
关注(0)|答案(2)|浏览(421)

如果你愿意,你可以直接跳到代码。前导文本是解释,但不是必要的。
我正在尝试使用SuperObject来解析 Delphi 。
我只是使用了 Delphi 10.4附带的普通JSON类,但在一些稍微复杂的功能上遇到了困难。
例如,诸如a.b.c是否存在,或者a.b.c.d-其中d是一个数组-或者a.b.c.d[3]之类的东西。
以及如何迭代a.b.c.d,并给a.b.c.d.e赋值,如果存在就更新,如果不存在就创建;并且,如果只存在路径的一部分,则创建全部路径,例如,只存在a.b,并且我想给a.b.c.d[3].e赋值。
如果有人能给我举几个这类事情的例子,我将不胜感激。
现在,对于我的问题,从不同的帖子中看起来超级对象将是答案,但是我在我的第一个基本步骤上失败了-测试嵌套的JSN元素的存在。
下面是我的代码(有没有在线JSON Fiddle站点?)

unit fMainForm;
interface
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses System.IOUtils,
     SuperObject;

procedure TForm1.FormCreate(Sender: TObject);
  var json: ISuperObject;
      jsonString : String;
begin    
  // Example JSON taken from https://stackoverflow.com/questions/10539797/complex-json-nesting-of-objects-and-arrays
  jsonString := '{' +
                '"problems": [{' +
                '    "Diabetes":[{' +
                '        "medications":[{' +
                '            "medicationsClasses":[{' +
                '                "className":[{' +
                '                    "associatedDrug":[{' +
                '                        "name":"asprin",' +
                '                        "dose":"",' +
                '                        "strength":"500 mg"' +
                '                    }],' +
                '                    "associatedDrug#2":[{' +
                '                        "name":"somethingElse",' +
                '                        "dose":"",' +
                '                        "strength":"500 mg"' +
                '                    }]' +
                '                }],' +
                '                "className2":[{' +
                '                    "associatedDrug":[{' +
                '                        "name":"asprin",' +
                '                        "dose":"",' +
                '                        "strength":"500 mg"' +
                '                    }],' +
                '                    "associatedDrug#2":[{' +
                '                        "name":"somethingElse",' +
                '                        "dose":"",' +
                '                        "strength":"500 mg"' +
                '                    }]' +
                '                }]' +
                '            }]' +
                '        }],' +
                '        "labs":[{' +
                '            "missing_field": "missing_value"' +
                '        }]' +
                '    }],' +
                '    "Asthma":[{}]' +
                '}]}';

  json := SO(jsonString);

  if  json.AsObject.Exists('problems') then
    Memo1.Lines.Add('"problems" found')
  else
    Memo1.Lines.Add('"problems" not found');

  if  json.AsObject.Exists('problems.Diabetes') then
    Memo1.Lines.Add('"problems.Diabetes" found')
  else
    Memo1.Lines.Add('"problems.Diabetes" not found');
end;

end.

当我运行它的时候,备忘录包含了
发现“问题”
未找到“糖尿病”
如何测试problems.Diabetes是否存在?
如果我能破解这个问题,我将尝试更新associatedDrugstrength,然后将新的键/值对插入到associatedDrug中,然后通过添加几个深度来扩展现有的键。

dsekswqp

dsekswqp1#

您选择了一个最糟糕的JSON示例,因为它的结构不必要地将所有内容放入数组中(总是[{]})当数组元素已经足够的时候。你应该抓住一个更简单的例子,从那个开始,来熟悉什么是对象,什么是数组。同样,我重组并缩短了JSON数据,使其更小,更清晰。如果您设法理解您可以继续并到达您的strength属性:

uses
  SuperObject;

var
  json, next: ISuperObject;
  text: String;
  sts: TSuperTableString;
  sa: TSuperArray;
  i: Integer;
begin
  text:=
  '{' +                        // {Object} starts
  '  "problems": [' +          //   1st "property" of object, value is an [array]
  '    {' +                    //     1st [element] of array is an {object}
  '      "Diabetes": "yes"' +  //       1st "property" of object is a "text"
  '    }' +                    //     {Object} ends after just 1 "property"
  '  ],' +                     //   [Array] ends after just 1 [element]
  '  "Asthma": [' +            //   2nd "property" of object, value is an [array] again
  '    {}' +                   //     1st [element] of array is an (empty) {object}
  '  ]' +                      //   [Array] ends after just 1 [element]
  '}';                         // {Object} ends after 2 "properties"

  json:= SO( text );

  if json.IsType( stObject ) then begin  // Is this even JSON (which must be an object)?
    sts:= json.AsObject;
    if sts.Find( 'problems', next ) then begin  // Does a property "problems" exist?
      if next.IsType( stArray ) then begin  // Is its value an array?
        sa:= next.AsArray;
        for i:= 0 to sa.Length- 1 do begin  // Iterate all array elements
          next:= sa[i];
          if next.IsType( stObject ) then begin  // Is this element an object?
            sts:= next.AsObject;

            sts.S['key']:= 'value';  // Adding our own property "key" to that object

            if sts.Find( {'Diabetes'} 'key', next ) then begin  // Does a property "key" exist?
              Caption:= 'Found it!';
              if next.IsType( stString ) then begin  // Is the property of type "text"?
                Caption:= Caption+ ' Value='+ next.AsString;  // Should be "value"
              end;
              break;  // Leave array loop
            end;
          end;
        end;
      end;
    end;
  end;
end;

使用调试器单步调试它,看看最终到达属性Diabetes所需的每个检查,然后检查它的值是否实际上是文本(而不是另一个对象/数组)。
初始JSON数据的一个更好的格式应该是这样的,摆脱了不必要的数组,还使用数字作为数据类型,而不仅仅是文本(语法是有效的,可能看起来有点奇怪,但我认为这是一个更合乎逻辑的显示):

{ "problems": 
  { "Diabetes": 
    { "medications":
      [
        [
          { "name": "Asprin"
          , "strength_mg": 500
          }
        ,
          { "name": "Arsen"
          , "strength_mg": 20
          }
        ]
      ,
        [
          { "name": "Toracin"
          , "strength_ml": 10
          }
        ,
          { "name": "Ambroxol"
          , "strength_mg": 350
          }
        ]
      ]
    , "labs": 
      { "test_chamber": 3
      }
    }
  , "Asthma": null
  }
, "is_insured": false
}
jucafojl

jucafojl2#

您有一个数组problems和另一个数组Diabetes。您可以简单地执行以下操作:

if Assigned(json['problems[0].Diabetes[0]']) then
    Memo1.Lines.Add('problems found + Diabetes found');

或在两个数组内循环:

if Assigned(json['problems']) then
  begin
    for i := 0 to json['problems'].AsArray.Length - 1 do
    begin
      Memo1.Lines.Add('"problems" found');

      if Assigned(json['problems'].AsArray[i]['Diabetes']) then
      begin
        for j := 0 to json['problems'].AsArray[i]['Diabetes'].AsArray.Length - 1 do
          Memo1.Lines.Add('"problems.Diabetes" found')
      end
      else
        Memo1.Lines.Add('"problems.Diabetes" not found');
    end;
  end
  else
    Memo1.Lines.Add('"problems" not found');

如果你不熟悉 Delphi / JSON,使用System.JSON比这个外部库更容易使用

相关问题