Delphi: Accessing JSON Objects within a JSON Array
Asked Answered
S

3

7

I have a JSON Object, let's name it jObject that looks like this:

{
  "id": 0,
  "data": "[{DAT_INCL: \"08/03/2012 10:07:08\", NUM_ORDE: 1, NUM_ATND: 1, NUM_ACAO: 2, NUM_RESU: 3},
            {DAT_INCL: \"08/03/2012 10:07:09\", NUM_ORDE: 2, NUM_ATND: 1, NUM_ACAO: 4, NUM_RESU: 5},
            {DAT_INCL: \"08/03/2012 10:07:09\", NUM_ORDE: 3, NUM_ATND: 1, NUM_ACAO: 8, NUM_RESU: NULL}]"
}

As you can see, it contains two pairs, one of which is an array with three objects in this case (the amount of objects is dynamic) with multiple "key: values"(these don't vary, being always the same 5 fields), which I want to insert into an SQL database, "key" being column, "value" being field. Question is, how do I access each object individually?

Code-wise what I did was extract the pair that contained this array by putting it in jPair

jPair := OriginalObject.Get(1); 

and then captured the array

jArray:= TJSONArray(jPair.JsonValue);

(Also, as a bonus, when I evaluate jArray.Size, the result is 6226004. What?)

Swig answered 7/3, 2012 at 20:46 Comment(2)
I'm using XE2 with DBXJSON and DBXJSONReflect.Swig
I originally had a different JSONObject, so basically code-wise what I did was extract the pair that contained this array by putting it in jPair (dtPair := OriginalObject.Get(1);) and then captured the array (jArray:= TJSONArray(jPair.JsonValue);) (Should I put this code in the original post?)Swig
S
11

If you have an array from DBXJSON, then it is a TJSONArray. Call its Get method to get an element of the array.

var
  Value: TJSONValue;

Value := jArray.Get(0);

You can also go through the entire array with a for loop:

for Value in jArray do

But if you check the Size property and get 6226004 instead of 3, that suggests there's something else wrong here. My guess is that what you think is a TJSONArray isn't really that type. Use as to do a checked type cast:

jArray := jPair.JsonValue as TJSONArray;

You'll get an EInvalidCast exception if that fails.

Sparerib answered 7/3, 2012 at 21:20 Comment(7)
Indeed I got an EInvalidCast Exception. Does that mean that the array I have in my JsonObject is not actually an array? Working with JSON is becoming more and more of an uphill battle.Swig
It means it's not a TJSONArray. The debugger should be able to tell you what it really is. If the debugger doesn't tell you in a tool tip, then display the result of calling jPair.JsonValue.ClassName.Sparerib
Yeah, it's a TJSONString, and a badly formatted one at that. How the heck am I gonna parse through this?Swig
It appears to be a string that contains more JSON data. Parse it the same way you parse other JSON-formatted strings of data. And then complain to the person responsible for generating that data because it's double-encoded.Sparerib
I was able to extract it down to the JsonString, and that contains my JsonArray. I can't figure out how to remove the JSONArray from the JSONString though, so I might as well bother you some more.Swig
I don't understand what further problem you're having. You can construct a JSON object from a string the same way you always do. Use TJSONObject.ParseJSONValue. Call it on your string: jArray := TJSONObject.ParseJSONValue((jPair.JsonValue as TJSONString).Value) as TJSONArray.Sparerib
"TJSONObject.ParseJSONValue((jPair.JsonValue as TJSONString).Value)" seems to be returning nil.Swig
T
6

here is an sample code to parse and output your json data. I've modified your JSON data and added ArrayData field, wich contains your initial array of objects:

program Project1;
{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils, dbxjson;

const JSON_DATA = '{"ArrayData":['+
                    '{"DAT_INCL":"07/03/2012 17:33:03", "NUM_ORDE":1,"NUM_ATND":1, "NUM_ACAO":2, "NUM_RESU":3},'+
                    '{"DAT_INCL":"07/03/2012 17:33:05", "NUM_ORDE":2,"NUM_ATND":1, "NUM_ACAO":4, "NUM_RESU":5},'+
                    '{"DAT_INCL":"07/03/2012 17:33:05", "NUM_ORDE":3,"NUM_ATND":1, "NUM_ACAO":8, "NUM_RESU":null}'+
                   ']}';


var jsv   : TJsonValue;
    originalObject : TJsonObject;

    jsPair : TJsonPair;
    jsArr : TJsonArray;
    jso  : TJsonObject;
    i : integer;
begin
    try
        //parse json string
        jsv := TJSONObject.ParseJSONValue(JSON_DATA);
        try
            //value as object
            originalObject := jsv as TJsonObject;

            //get pair, wich contains Array of objects
            jspair := originalObject.Get('ArrayData');
            //pair value as array
            jsArr := jsPair.jsonValue as  TJsonArray;

            writeln('array size: ', jsArr.Size);
            //enumerate objects in array
            for i := 0 to jsArr.Size - 1 do begin
                writeln('element ', i);
                // i-th object
                jso := jsArr.Get(i) as TJsonObject;

                //enumerate object fields
                for jsPair in jso do begin
                    writeln('   ', jsPair.JsonString.Value, ': ', jsPair.JsonValue.Value);
                end;
            end;
        finally
            jsv.Free();
            readln;
        end;
    except
        on E: Exception do
          Writeln(E.ClassName, ': ', E.Message);
    end;
end.
Timorous answered 8/3, 2012 at 10:52 Comment(1)
Thanks for your example it helped me. However instead of iterating over the size of the array you can for jsValue in jsArr do begin jsObj := jsValue as TJSONObject; It just reads much cleaner to me.Valina
C
1

Practical example of adding JSON data from an array to a TComboBox

This example assumes you have included the JSON unit. It also assumes you have a TComboBox named cmbCompany. There is nothing wrong with the accepted answers, I just wanted to document.

uses JSON;

procedure LoadCompanies;
var
  i : Integer;
  companyArray : TJsonArray;
  company : TJsonObject;

begin
  //get the company data
  companyData := TJSONObject.ParseJSONValue('{data:[{"name": "One"},{"name": "Two"}]}') as TJSONObject;
  try
    cmbCompany.Items.Clear;
    with companyData do
    begin
      //Important bit which relates to the question!
      companyArray := (Get('data').JsonValue as TJSONArray);
      try 
        for i := 0 to companyArray.Size-1 do
        begin
          //Get one of the array values
          company := (companyArray.Get(i) as TJSONObject);

          //Add name to combo box, you can obviously get other values in similar fashion
          cmbCompany.Items.Add(company.GetValue<String>('name'));
        end;
      finally
        companyArray.Free;
      end;
    end;
  finally
    companyData.Free;
  end;
end;
Clump answered 29/12, 2021 at 11:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.