TransWikia.com

Delphi Parse JSON

Stack Overflow Asked by Stanley Mladenek on February 17, 2021

I need to read the fuelTanks value. Everything before that goes to me / in fact there are more items /, but I don’t know how to read the fuelTanks field.

My current code:

procedure TMain.JsonAktStav;
var
  JSonObject: TJSonObject;
  data: TJSONArray;
  JSonValue: TJSonValue;
  //*** bJSon is the TByteStream from the previous procedure ***
  idx: integer;
begin
  JSonObject := TJSonObject.Create;
  JSonValue := JSonObject.ParseJSONValue(bJSON.Bytes, 0, bJSON.Size) as TJSONObject;
  JSonValue := (JSonValue as TJSONObject).Get('response').JSonValue;
  JSonValue := (JSonValue as TJSONObject).Get('data').JSonValue;
    
  data := JSonValue as TJSONArray;
    
  for idx := 0 to data.Size - 1 do
  begin
    if (JSonValue is TJSONArray) then
      vehicleid := ((JSonValue as TJSONArray).Items[idx] as TJSonObject).Get('vehicleid').JSonValue.Value;  
  end;

  JSonObject.Free;
  bJSON.Free;
end;

TIdHTTP will return the JSON response, which is listed below:

{
    "response": {
        "actionName": "getActualStates",
        "code": 200,
        "data": [
            {
                "vehicleid": 4500,
                "temperatures": [],
                "fuelTanks": [
                    {
                        "fuelTankNumber": 1,
                        "status": 247
                    },
                    {
                        "fuelTankNumber": 2,
                        "status": 65
                    }
                ]
            },
            {
                "vehicleid": 4751,
                "temperatures": [],
                "fuelTanks": [
                    {
                        "fuelTankNumber": 1,
                        "status": 462
                    },
                    {
                        "fuelTankNumber": 2,
                        "status": 380
                    }
                ]
            }
        ]
    }
}

I can’t read "fuelTankNumber" and "status".

2 Answers

fuelTanks is an array of objects, and you already know how to access child fields that are arrays and objects, so you just need to expand your code further to iterate deeper into the JSON structure, eg:

procedure TMain.JsonAktStav;
var
  JSonValue: TJSonValue;
  data, fuelTanks: TJSONArray;
  vehicle, fuelTank: TJSonObject;
  idx, idx2: integer;
  vehicleid, fuelTankNumber, status: integer;
begin
  try
    //*** bJSon is the TByteStream from the previous procedure ***
    JSonValue := JSonObject.ParseJSONValue(bJSON.Bytes, 0, bJSON.Size);
    if JSonValue <> nil then
    try
      JSonObject := JSonValue as TJSONObject;

      JSonObject := JSonObject.GetValue<TJSONObject>('response');
      data := JSonObject.GetValue<TJSONArray>('data');

      for idx := 0 to data.Size - 1 do
      begin
        vehicle := data.Items[idx] as TJSONObject;

        vehicleid := vehicle.GetValue<Integer>('vehicleid');

        // use vehicleid as needed...

        fuelTanks := vehicle.GetValue<TJSONArray>('fuelTanks');
        
        for idx2 := 0 to fuelTanks.Size - 1 do
        begin
          fuelTank := fuelTanks.Items[idx2] as TJSONObject;

          fuelTankNumber := fuelTank.GetValue<Integer>('fuelTankNumber');
          status := fuelTank.GetValue<Integer>('status');

          // use fuelTankNumber and status as needed...
        end;
      end;
    finally
      JSonValue.Free;
    end;
  finally
    bJSON.Free;
  end;
end;

Answered by Remy Lebeau on February 17, 2021

As I told before, I think the best way to work with JSON is serialization and deserialization.

So, first of all you have to describe objects that represents your json (I've made it in unit):

unit Unit3;

interface
TYPE
TMyDoubleArray = Array OF double;

TMyFuelObject = CLASS(TObject)
  PRIVATE
    FFuelTankNumber:integer;
    FStatus:integer;
    procedure SetFuelTankNumber(const Value: integer);
    procedure SetStatus(const Value: Integer);
  PUBLIC
    property fuelTankNumber:integer read FFuelTankNumber write SetFuelTankNumber;
    property status:Integer read FStatus WRITE SetStatus;
END;

TMyFuelArray = ARRAY OF TMyFuelObject;

TMyAnotherOneInnerObject = CLASS(TObject)
  private
    FVehicleId:Integer;
    FTemperatures:TMyDoubleArray;
    FFuelTanks:TMyFuelArray;
    procedure SetFuelTanks(const Value: TMyFuelArray);
    procedure SetTemperatures(const Value: TMyDoubleArray);
    procedure SetVehicleId(const Value: integer);
  PUBLIC
    property vehicleid:integer read FVehicleId WRITE SetVehicleId;
    property temperatures:TMyDoubleArray read FTemperatures write SetTemperatures; //Is it double?
    property fuelTanks:TMyFuelArray read FFuelTanks write SetFuelTanks;
END;

TMyInnerArray = ARRAY of TMyAnotherOneInnerObject;

TMyInnerObject = CLASS(TObject)
  PRIVATE
    FActionName:String;
    FCode:SmallInt;
    FData:TMyInnerArray;
    procedure SetActionName(const Value: String);
    procedure SetCode(const Value: SmallInt);
    procedure SetData(const Value: TMyInnerArray);
  PUBLIC
    property actionName:String read FActionName write SetActionName;
    PROPERTY code:SmallInt read FCode write SetCode;
    PROPERTY data:TMyInnerArray read FData write SetData;
END;

TMyObject = CLASS(TObject)
  PRIVATE
    FResponse:TMyInnerObject;
    procedure SetResponse(const Value: TMyInnerObject);
  PUBLIC
    PROPERTY response:TMyInnerObject READ FResponse WRITE SetResponse;
END;

implementation

{ TMyObject }

procedure TMyObject.SetResponse(const Value: TMyInnerObject);
begin
  FResponse := Value;
end;

{ TMyInnerObject }

procedure TMyInnerObject.SetActionName(const Value: String);
begin
  FActionName := Value;
end;

procedure TMyInnerObject.SetCode(const Value: SmallInt);
begin
  FCode := Value;
end;

procedure TMyInnerObject.SetData(const Value: TMyInnerArray);
begin
  FData := Value;
end;

{ TMyAnotherOneInnerObject }

procedure TMyAnotherOneInnerObject.SetFuelTanks(const Value: TMyFuelArray);
begin
  FFuelTanks := Value;
end;

procedure TMyAnotherOneInnerObject.SetTemperatures(const Value: TMyDoubleArray);
begin
  FTemperatures := Value;
end;

procedure TMyAnotherOneInnerObject.SetVehicleId(const Value: integer);
begin
  FVehicleId := Value;
end;

{ TMyFuelObject }

procedure TMyFuelObject.SetFuelTankNumber(const Value: integer);
begin
  FFuelTankNumber := Value;
end;

procedure TMyFuelObject.SetStatus(const Value: Integer);
begin
  FStatus := Value;
end;

end.

Yes, there is a plenty of code. But if trying to work with this information in future it can be easier than parse every field in json.

Then you have to parse it. I've put your JSON into Memo on the form and implemented this OnButtonClick event:

uses ... REST.Json, Unit3;

...

procedure TForm2.Button1Click(Sender: TObject);
var json:string;
    myObject:TMyObject;
begin
  json := Memo1.Text;
  try 
     myObject := TJson.JsonToObject<TMyObject>(json);
     //do with myObject everything you want
  finally
     FreeAndNil(myObject);
  end;
end;

Then I got this:

Result in Delphi 10.1

To get values try this code:

if length(myObject.response.data) > 0 then
 for i := 0 to length(myObject.response.data) - 1 do
 with myObject.response.data[i] do
   if length(FuelTanks) > 0 then
   for j := 0 to length(FuelTanks) - 1 do
      ShowMessage(FuelTanks[j].FuelTankNumber.ToString); // or inttostr(FuelTanks[j].FuelTankNumber)

Answered by mrNone on February 17, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP