Delphi解析JSON数组或数组

Raf*_*ssi 7 delphi json

这是我希望能够解析的示例 JSON:

[
  {
    "a":{
      "username":"aaa",
      "email":"aaa@gmail.com"
    }
  },
  {
    "b":{
      "username":"bbb",
      "email":"bbb@gmail.com"
    }
  }
]
Run Code Online (Sandbox Code Playgroud)

我需要调用getData('b', 'email')must 输出bbb@gmail.com


我真的很难理解如何使用该System.JSON单元,但我无法得到解决方案!我希望能够编写一个从上述 JSON 结构中提取特定数据的函数。到目前为止,这是我的代码。在类构造函数中,我有:

var
  FIds: TJSONArray;
begin
  FIds := TJSONObject.ParseJSONValue({json string here}) as TJSONArray;
end;
Run Code Online (Sandbox Code Playgroud)

然后,在必须返回数据的函数中,我写了这个:

// 'name' can be 'a' or 'b'  | 'data' can be 'username' or 'email'
function TTest.getData(const name, data: string): string;
var
  FValue, FValueInner: TJSONValue;
begin
  for FValue in Fids do
  begin
    if (FValue is TJSONArray) then
    begin
      //Here I am sure that I have a TJSONArray (which can be 'a' or 'b' from above)
    end;
  end;
end;
Run Code Online (Sandbox Code Playgroud)

根据我上面写的,我必须检查 的值name并决定是否必须访问a或里面的数据b。然后,一旦我选择了正确的 JSON 数组aor b,我必须选择是否要显示usernameemail字段(在data变量中指定)。

我怎样才能做到这一点?


这是我最近的尝试,但我真的不明白该怎么做:

... same code above ...

if (FValue is TJSONArray) then
begin
  //here I want to check if the current array is a or b
  if ((FValue as TJSONArray).Items[0] as TJSONValue).Value = name then
  begin
    Farr := TJSONObject.ParseJSONValue(((FValue as TJSONArray).Items[0] as TJSONValue).ToJSON) as TJSONArray;
    try
      //here I want to get the data inside username or email
      for FValueInner in Farr do
        Result := FValueInner.GetValue<string>(data);
    finally
      Farr.Free;
    end;
  end;
end;
Run Code Online (Sandbox Code Playgroud)

哪里Farr: TJSONArray;FValueInner: TJSONValue;

Mac*_*ace 10

对于寻找这些答案的新读者。

这个函数怎么样,或者如果你重组 JSON 数据甚至更简单?

function getData(JsonString: String; User: String; Field: String): String;
var
  JSonValue: TJSonValue;
  JsonArray: TJSONArray;
  ArrayElement: TJSonValue;
  FoundValue: TJSonValue;
begin
  Result :='';

  // create TJSonObject from string
  JsonValue := TJSonObject.ParseJSONValue(JsonString);

  // get the array
  JsonArray := JsonValue as TJSONArray;

  // iterate the array
  for ArrayElement in JsonArray do begin
      FoundValue := ArrayElement.FindValue(User);
      if FoundValue <> nil then begin
        Result := ArrayElement.GetValue<string>(User + '.' + Field);
        break;
      end;
  end;
end;
Run Code Online (Sandbox Code Playgroud)

上面示例 JSON 代码的问题在于它使用用户名“a”“b”作为用户数据的JSON 键{key:data}。这样您就不能在搜索数据时使用 GetValue("a") 。以不同方式构建 JSON 数据可以使搜索过程更加轻松。我稍后会举一个例子。

处理给定 JSON 数据的一种方法是使用FindValue,这样您就可以检查键为“a”或“b”的字段是否存在。

FoundValue := ArrayElement.FindValue("b");
if FoundValue <> nil then begin
    Result := ArrayElement.GetValue<string>("b"+ '.' + "email");
    break;
Run Code Online (Sandbox Code Playgroud)

关于“解析 JSON 数组”问题:将数据作为 TJSonObject 加载后,您可以将数据更改为 TJSONArray 并迭代元素。

  JsonValue := TJSonObject.ParseJSONValue(JsonString);  
  JsonArray := JsonValue as TJSONArray;
  for ArrayElement in JsonArray do begin
    ...
Run Code Online (Sandbox Code Playgroud)

给定 JSON 数据的工作示例代码:

unit JsonArray1;

interface

uses System.JSON;

function getData2(JsonString: String; User: String; Field: String): String;
procedure Test1();

implementation

function getData2(JsonString: String; User: String; Field: String): String;
var
  JSonValue: TJSonValue;
  JsonArray: TJSONArray;
  ArrayElement: TJSonValue;
  FoundValue: TJSonValue;
begin
  Result :='';

  // create TJSonObject from string
  JsonValue := TJSonObject.ParseJSONValue(JsonString);

  // get the array
  JsonArray := JsonValue as TJSONArray;

  // iterate the array
  for ArrayElement in JsonArray do begin
      FoundValue := ArrayElement.FindValue(User);
      if FoundValue <> nil then begin
        Result := ArrayElement.GetValue<string>(User + '.' + Field);
        break;
      end;
  end;
end;

procedure Test1();
var
  DataBase: String;
  EmailAddress : String;
  Username: String;
begin
  DataBase := '[  {"a" : {"username":"aaa","email":"aaa@gmail.com"}},' +
                 '{"b" : {"username":"bbb","email":"bbb@gmail.com"}}  ]';

  EmailAddress := getData2(DataBase, 'b', 'email');
  Username := getData2(DataBase, 'a', 'username');

end;

end.
Run Code Online (Sandbox Code Playgroud)

如前所述,使用适当的键重构 JSON 数据使查找数据的代码更加简单。因为用户数据 "a":{}, "b":{} 之间存在 1 对 1 关系,所以很容易引入“用户”键。还将“用户”键添加到数组会导致所有数据都具有键。

  '{"users" : [{ "user":"a", "username":"aaa","email":"aaa@gmail.com"},' +
              '{ "user":"b", "username":"bbb","email":"bbb@gmail.com"}]}';
Run Code Online (Sandbox Code Playgroud)

当您迭代用户时,您现在可以使用带有新“用户”键的 GetValue。

  if ArrayElement.GetValue<String>('user') = 'b' then begin
    Result := ArrayElement.GetValue<String>('email');
Run Code Online (Sandbox Code Playgroud)

通过给数组一个键,你现在可以得到数组:

JsonArray := JsonValue.GetValue<TJSONArray>('users');
Run Code Online (Sandbox Code Playgroud)

重组 JSON 数据的工作示例代码:

unit JsonArray2;

interface

uses System.JSON;

function getData2(JsonString: String; User: String; Field: String): String;
procedure Test2();

implementation

function getData2(JsonString: String; User: String; Field: String): String;
var
  JSonValue: TJSonValue;
  JsonArray: TJSONArray;
  ArrayElement: TJSonValue;
  FoundValue: TJSonValue;
begin
  Result :='';

  // create TJSonObject from string
  JsonValue := TJSonObject.ParseJSONValue(JsonString);

  // get the array
  JsonArray := JsonValue.GetValue<TJSONArray>('users');

  // iterate the array
  for ArrayElement in JsonArray do begin
      if ArrayElement.GetValue<String>('user') = User then begin
        Result := ArrayElement.GetValue<String>(Field);
        break;
      end;
  end;
end;

procedure Test2();
var
  DataBase: String;
  EmailAddress : String;
  Username: String;
begin
  DataBase := '{"users" : [{ "user":"a", "username":"aaa","email":"aaa@gmail.com"},' +
                          '{ "user":"b", "username":"bbb","email":"bbb@gmail.com"}]}';

  EmailAddress := getData2(DataBase, 'b', 'email');
  Username := getData2(DataBase, 'a', 'username');

end;

end.
Run Code Online (Sandbox Code Playgroud)


Rem*_*eau 5

您的 JSON 是一个对象数组,FIds一个TJSONArray包含TJSONObject元素也是如此。这些对象的ab字段本身就是对象,而不是数组。因此,FValue is TJSONArray在枚举该数组时将始终为 false。

另外,(FValue as TJSONArray).Items[0] as TJSONValue).Value = name是错误的,因为 JSON 对象包含名称/值对,但是您忽略了名称,并且您试图枚举这些对,好像它们是数组的元素,而实际上它们不是。如果要枚举对象的对,请使用TJSONObject.CountandTJSONObject.Pairs[]属性。但是在这种情况下这不是必需的,因为您正在按名称查找特定的对。 TJSONObject具有Values[]用于该目的的属性。

而且TJSONObject.ParseJSONValue(((FValue as TJSONArray).Items[0] as TJSONValue).ToJSON) as TJSONArray简直是荒谬可笑。没有理由将对象转换回 JSON 字符串只是为了再次解析它。已经解析过一次,不需要再次解析。

最后,FValueInner.GetValue<string>(data)是错误的,因为TJSONValue没有GetValue()方法,更不用说使用泛型的方法了。

现在,话虽如此,请尝试更像这样的事情:

// 'name' can be 'a' or 'b'  | 'data' can be 'username' or 'email'
function TTest.getData(const name, data: string): string;
var
  FValue, FValueInner: TJSONValue;
begin
  Result := '';
  for FValue in Fids do
  begin
    if (FValue is TJSONObject) then
    begin
      FValueInner := TJSONObject(FValue).Values[name];
      if FValueInner <> nil then
      begin
        if (FValueInner is TJSONObject) then
        begin
          FValueInner := TJSONObject(FValueInner).Values[data]; 
          if FValueInner <> nil then
            Result := FValueInner.Value;
        end;
        Exit;
      end;
    end;
  end;
end;
Run Code Online (Sandbox Code Playgroud)