Search code examples
arraysjsondelphi

How to count the number of Items in a TJSONArray?


I am making my first steps with JSON and I am looking for a solution to get the number of items in a TJSONArray. I need the number to count up in a For Loop.

The following code is working for me, just the count up which is now set to 5 should be replaced by number of items in the array. I already tried JsonArray.Count-1, which according to my research should be the right way, but just replacing the number by JsonArray.Count-1 results in an Access Violation.

var
  JSonObject: TJSonObject;
  JSonValue: TJSonValue;
  JSOnArray: TJsonArray;
  st: string;
  id, name, description, sku, price: string;
  i, j: integer;
begin
  st := Memo1.Text;

  j := 1;
  if Assigned(JSONArray) then
  begin

    For i := 0 to 5 -1 do
    Begin
      JSonObject := TJSonObject.Create;
      JsonValue:=JSonObject.ParseJSONValue(st);
      if (JSONValue is TJSONArray) then
      Begin
        id := ((JSONValue as TJSONArray).Items[i] as TJSonObject).Get('id').JSONValue.Value;
        sku := ((JSONValue as TJSONArray).Items[i] as TJSonObject).Get('sku').JSONValue.Value;
        description := ((JSONValue as TJSONArray).Items[i] as TJSonObject).Get('description').JSONValue.Value;
        name := ((JSONValue as TJSONArray).Items[i] as TJSonObject).Get('name').JSONValue.Value;
        price := ((JSONValue as TJSONArray).Items[i] as TJSonObject).Get('price').JSONValue.Value;
        stringgrid1.Cells[1,j] := sku;
        stringgrid1.Cells[2,j] := name;
        stringgrid1.Cells[4,j] := description;
        stringgrid1.Cells[3,j] := price;
        j:=j+1;
      End;
    End;

    JSonObject.Free;
  end;

Solution

  • JsonArray.Count is the correct value to use. However, the Access Violation is because JsonArray is still unassigned at the point where you try to evaluate the for loop.

    The way you have written your code, your for loop is re-parsing the same JSON over and over 1, accessing a different array element each time. That is why things seemingly work when you hard-code the count.

    • 1: You are also leaking every TJsonObject you create except the last one, and also leaking every TJsonValue that ParseJsonValue() returns.

    The fix is to parse the JSON before you run the loop. Don't parse the JSON inside of the loop.

    Also, you do not need to create a TJSONObject instance to call ParseJSONValue(), as it is a class static method. You can call it directly on the TJSONObject class itself.

    Try something more like this:

    var
      JSonObject: TJSonObject;
      JSonValue: TJSonValue;
      JSonArray: TJsonArray;
      id, name, description, sku, price: string;
      i, j: integer;
    begin
      JsonValue := TJSONObject.ParseJSONValue(Memo1.Text);
      if Assigned(JsonValue) then
      try
        JSonArray := JsonValue as TJSONArray;
        j := 1;
        for i := 0 to JSonArray.Count-1 do
        begin
          JSonObject := JSonArray.Items[i] as TJSonObject;
    
          id := JSonObject.GetValue('id').Value;
          sku := JSonObject.GetValue('sku').Value;
          description := JSonObject.GetValue('description').Value;
          name := JSonObject.GetValue('name').Value;
          price := JSonObject.GetValue('price').Value;
    
          StringGrid1.Cells[1,j] := sku;
          StringGrid1.Cells[2,j] := name;
          StringGrid1.Cells[3,j] := price;
          StringGrid1.Cells[4,j] := description;
    
          Inc(j);
        end;
      finally
        JsonValue.Free;
      end;
    end;