Raffaele Rossi Raffaele Rossi - 1 year ago 417
JSON Question

Delphi parse JSON array or array

This is the sample JSON I want to be able to parse:

[
{
"a":{
"username":"aaa",
"email":"[email protected]"
}
},
{
"b":{
"username":"bbb",
"email":"[email protected]"
}
}
]


I need that a call to
getData('b', 'email')
must output !




I am really struggling to understand how to use the
System.JSON
unit, but I can't get the solution! I want to be able to write a function that extracts a particular data from the above kind of JSON structure. This is my code so far. In the class constructor I have:

var
FIds: TJSONArray;
begin
FIds := TJSONObject.ParseJSONValue({json string here}) as TJSONArray;
end;


Then, inside the function that must return the data, I have written this:

// '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;


According to what I have written above, I have to check the value of
name
and decide if I have to access the data inside
a
or
b
. Then, once I have picked the correct JSON array
a
or
b
, I have to select if I want to display the
username
or the
email
field (which is specified inside the
data
variable).

How can I do this?




This is my latest attempt but I really can't understand what to do:

... 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;


Where
Farr: TJSONArray;
and
FValueInner: TJSONValue;

Answer Source

Your JSON is an array of objects, so FIds is a TJSONArray containing TJSONObject elements. And the a and b fields of those objects are themselves objects, not arrays. So FValue is TJSONArray will always be false while enumerating that array.

Also, (FValue as TJSONArray).Items[0] as TJSONValue).Value = name is wrong, because a JSON object contains name/value pairs, but you are ignoring the names, and you are trying to enumerate the pairs as if they are elements of an array when they are really not. If you want to enumerate an object's pairs, use the TJSONObject.Count and TJSONObject.Pairs[] property. But that is not necessary in this situation since you are looking for a specific pair by its name. TJSONObject has a Values[] property for that very purpose.

And TJSONObject.ParseJSONValue(((FValue as TJSONArray).Items[0] as TJSONValue).ToJSON) as TJSONArray is just plain ridiculous. There is no reason to convert an object back to a JSON string just to parse it again. It has already been parsed once, you don't need to parse it again.

And lastly, FValueInner.GetValue<string>(data) is wrong, because TJSONValue does not have a GetValue() method, let alone one that uses Generics.

Now, with that said, try something more like this instead:

// '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;
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download