Jump to content

Recommended Posts

HI all

just need a bit of help using Delphi's json functions please 🙂

I have this code working OK

e.g

  st := tempstr;
   JSonObject := TJSonObject.Create;
   JsonValue:=JSonObject.ParseJSONValue(st);
   JsonValue:=(JsonValue as TJSONObject).Get('data').JSONValue;
   JsonValue:=(JsonValue as TJSONObject).Get('conditions').JSONValue;
   if (JSONValue is TJSONArray) then
   begin
      Branch := ((JSONValue as TJSONArray).Items[0] as TJSonObject).Get('temp').JSONValue.Value;
 end;

  JSonObject.Free;

 

but I want to get data from a data pair that is on a second bracketed data

ie. it works as above for the first data array

but the json data has another data array

i.e

first data array pairs},{second data array pairs

 

how to I read from the second data array ?

thanks!

(just putting the name in as in the branch code above that is in the second data array causes an error

🙂

 

 

 

Edited by mewindy

Share this post


Link to post
11 hours ago, mewindy said:

   JSonObject := TJSonObject.Create;

   JsonValue:=JSonObject.ParseJSONValue(st);

ParseJSONValue() is a 'class' method, so you don't need to create a TJSONObject instance in order to call it:

JsonValue := TJSONObject.ParseJSONValue(st);
11 hours ago, mewindy said:

   JsonValue:=(JsonValue as TJSONObject).Get('data').JSONValue;

This is creating a memory leak, because you are losing your pointer to the original TJSONValue object that ParseJSONValue() returns.  You need to Free() that original object when you are done using it.  You are not doing that.  You should use additional variables for your typecasts, eg:

var
  ...
  JsonValue: TJSONValue;
  JSonObject: TJOSNObject;
  JsonData: TJSONObject;
  JsonConditions: TJSONValue;
begin
  ...
  JsonValue := TJSONObject.ParseJSONValue(st);
  if JsonValue <> nil then
  try
    JsonObject := JsonValue as TJSONObject;
    JsonData := JsonObject.GetValue('data') as TJSONObject;
    JsonConditions := JsonData.GetValue('conditions');
    if (JsonConditions is TJSONArray) then
    begin
      JsonObject := (JsonConditions as TJSONArray).Items[0] as TJSONObject;
      Branch := JsonObject.GetValue('temp').Value;
    end;
  finally
    JsonValue.Free; 
  end;
  ...
end;
11 hours ago, mewindy said:

but I want to get data from a data pair that is on a second bracketed data

A "second bracketed data" of what exactly?  Which element of the JSON document has the pairs you are looking for?  You need to be more specific.

11 hours ago, mewindy said:

ie. it works as above for the first data array

but the json data has another data array

Are you referring to the "conditions" array?  If so, then simply use Items[1] to access the second array element, Items[2] for the third element, etc.

 

If that is not what you need, then what is stopping you from accessing the desired second array?  What are you actually stuck on?  Where is that array located exactly?

11 hours ago, mewindy said:

how to I read from the second data array ?

It is really hard to help you with that when you have not shown the actual JSON you are working with.  Please show the actual JSON.

 

Share this post


Link to post

HI

thanks for the help so far

here is the raw data to st as

{"data":{"did":"001D0A710197","ts":1557136813,"conditions":[{"lsid":223656,"data_structure_type":1,"txid":1,"temp": 52.7,"hum":66.3,"dew_point": 41.8,"wet_bulb": 46.2,"heat_index": 51.7,"wind_chill": 52.7,"thw_index": 51.7,"thsw_index": 49.7,"wind_speed_last":0.00,"wind_dir_last":0,"wind_speed_avg_last_1_min":0.00,"wind_dir_scalar_avg_last_1_min":null,"wind_speed_avg_last_2_min":0.00,"wind_dir_scalar_avg_last_2_min":null,"wind_speed_hi_last_2_min":0.00,"wind_dir_at_hi_speed_last_2_min":0,"wind_speed_avg_last_10_min":0.00,"wind_dir_scalar_avg_last_10_min":null,"wind_speed_hi_last_10_min":0.00,"wind_dir_at_hi_speed_last_10_min":0,"rain_size":2,"rain_rate_last":0,"rain_rate_hi":0,"rainfall_last_15_min":0,"rain_rate_hi_last_15_min":0,"rainfall_last_60_min":0,"rainfall_last_24_hr":0,"rain_storm":null,"rain_storm_start_at":null,"solar_rad":0,"uv_index":0.0,"rx_state":0,"trans_battery_flag":0,"rainfall_daily":0,"rainfall_monthly":0,"rainfall_year":0,"rain_storm_last":null,"rain_storm_last_start_at":null,"rain_storm_last_end_at":null},{"lsid":223554,"data_structure_type":4,"temp_in": 69.1,"hum_in":38.2,"dew_point_in": 42.6,"heat_index_in": 66.8},{"lsid":223553,"data_structure_type":3,"bar_sea_level":29.932,"bar_trend": 0.028,"bar_absolute":29.404}]},"error":null}
 

 

if I use the code like


     JsonValue := TJSONObject.ParseJSONValue(st);
  if JsonValue <> nil then
  try
    JsonObject := JsonValue as TJSONObject;
    JsonData := JsonObject.GetValue('data') as TJSONObject;
    JsonConditions := JsonData.GetValue('conditions');
    if (JsonConditions is TJSONArray) then
    begin
      JsonObject := (JsonConditions as TJSONArray).Items[0] as TJSONObject;
      Branch:= JsonObject.GetValue('temp').Value;
      memo1.Lines.add('Parsed temperature '+branch);

     

    JsonObject := (JsonConditions as TJSONArray).Items[1] as TJSONObject;
      Branch:= JsonObject.GetValue('bar_sea_level').Value;
      memo1.Lines.add('Parsed barometer '+branch);

    end;
  finally
    JsonValue.Free;
  end;

 

 

then the  second part to get the bar_sea_level causes an access violation error (i.e I have tried access as items[1]

so I must be still doing something wrong

Edited by mewindy

Share this post


Link to post
12 hours ago, mewindy said:

if I use the code like

...
then the  second part to get the bar_sea_level causes an access violation error (i.e I have tried access as items[1]

so I must be still doing something wrong

The 2nd JSON object in the "conditions" array DOES NOT have a "bar_sea_level" value in it, so calling JsonObject.GetValue('bar_sea_level') returns nil.  The "bar_sea_level" value is actually in the 3rd JSON object in the array, so you need to use Items[2] instead of Items[1]:

var
  JsonValue: TJSONValue;
  JsonObject, JsonData: TJSONObject;
  JsonConditions: TJSONArray;
  Branch: string;
  ...
begin
  ...
  JsonValue := TJSONObject.ParseJSONValue(st);
  if JsonValue <> nil then
  try
    JsonObject := JsonValue as TJSONObject;
    JsonData := JsonObject.GetValue('data') as TJSONObject;
    JsonConditions := JsonData.GetValue('conditions') as TJSONArray;

    JsonObject := JsonConditions.Items[0] as TJSONObject;
    Branch := JsonObject.GetValue('temp').Value;
    memo1.Lines.add('Parsed temperature '+branch);

    JsonObject := JsonConditions.Items[2] as TJSONObject;
    Branch := JsonObject.GetValue('bar_sea_level').Value;
    memo1.Lines.add('Parsed barometer '+branch);

  finally
    JsonValue.Free;
  end;
  ...
end;

It helps to view the JSON in an indented format so you can more clearly see the actual hierarchy of values, objects, and arrays, eg:

{
  "data":{
    "did":"001D0A710197",
    "ts":1557136813,
    "conditions":[
      {
        "lsid":223656,
        "data_structure_type":1,
        "txid":1,
        "temp": 52.7,
        "hum":66.3,
        "dew_point": 41.8,
        "wet_bulb": 46.2,
        "heat_index": 51.7,
        "wind_chill": 52.7,
        "thw_index": 51.7,
        "thsw_index": 49.7,
        "wind_speed_last":0.00,
        "wind_dir_last":0,
        "wind_speed_avg_last_1_min":0.00,
        "wind_dir_scalar_avg_last_1_min":null,
        "wind_speed_avg_last_2_min":0.00,
        "wind_dir_scalar_avg_last_2_min":null,
        "wind_speed_hi_last_2_min":0.00,
        "wind_dir_at_hi_speed_last_2_min":0,
        "wind_speed_avg_last_10_min":0.00,
        "wind_dir_scalar_avg_last_10_min":null,
        "wind_speed_hi_last_10_min":0.00,
        "wind_dir_at_hi_speed_last_10_min":0,
        "rain_size":2,
        "rain_rate_last":0,
        "rain_rate_hi":0,
        "rainfall_last_15_min":0,
        "rain_rate_hi_last_15_min":0,
        "rainfall_last_60_min":0,
        "rainfall_last_24_hr":0,
        "rain_storm":null,
        "rain_storm_start_at":null,
        "solar_rad":0,
        "uv_index":0.0,
        "rx_state":0,
        "trans_battery_flag":0,
        "rainfall_daily":0,
        "rainfall_monthly":0,
        "rainfall_year":0,
        "rain_storm_last":null,
        "rain_storm_last_start_at":null,
        "rain_storm_last_end_at":null
      },
      {
        "lsid":223554,
        "data_structure_type":4,
        "temp_in": 69.1,
        "hum_in":38.2,
        "dew_point_in": 42.6,
        "heat_index_in": 66.8
      },
      {
        "lsid":223553,
        "data_structure_type":3,
        "bar_sea_level":29.932,
        "bar_trend": 0.028,
        "bar_absolute":29.404
      }
    ]
  },
  "error":null
}

Now you can clearly see that there are 3 objects in the "conditions" array.

Edited by Remy Lebeau
  • Like 2

Share this post


Link to post

OMG

you are correct!

I should have spotted that

its working now

thanks Remy!

Share this post


Link to post

procedure TCLOSINGForm.SpeedButton10Click(Sender: TObject);
var
  JsonValue: TJSONValue;
  JsonObject, JsonData: TJSONObject;
  JsonConditions: TJSONArray;
  Branch, st: string;
begin
  st :='iWN5p2qfRFeGKXn1m3iGnDW0Vkl2: {"PROFILE":{"BIRTHDAY":"8\/20\/19","FULL NAME":"","GENDER":"MALE","NATIONALITY":"INDONESIA","NICK NAME":"","OFFICE":"CLOSING SYSTEM","PHONE NO":"","REFERAL UID":"","WEDDING":"8\/20\/19"}}';
  JsonValue := TJSONObject.ParseJSONValue(st);
  if JsonValue <> nil then
  try
    JsonObject := JsonValue as TJSONObject;
    JsonData := JsonObject.GetValue('iWN5p2qfRFeGKXn1m3iGnDW0Vkl2') as TJSONObject;
    JsonConditions := JsonData.GetValue('PROFILE') as TJSONArray;

 

    JsonObject := JsonConditions.Items[0] as TJSONObject;
    Branch := JsonObject.GetValue('BIRTHDAY').Value;
    mem.Lines.add('Parsed BIRTHDAY '+branch);

 

    JsonObject := JsonConditions.Items[0] as TJSONObject;
    Branch := JsonObject.GetValue('FULL NAME').Value;
    mem.Lines.add('Parsed FULL NAME '+branch);

  finally
    JsonValue.Free;
  end;
end;

 

 

but it won't work...please need help/..

Share this post


Link to post
11 hours ago, Lie Ming said:

but it won't work...please need help/.

That is because there are two problems in your code:

  1. the JSON string you are passing in to ParseJSONValue() does not represent a JSON object, just a single JSON name/value pair, so your first typecast to TJSONObject will fail.  You need to wrap the entire JSON string in angle brackets, since ParseJSONValue() can't return a TJSONPair.
  2. The "PROFILE" field is not a JSON array, so your typecast to TJSONArray will fail.  The "PROFILE" field is a JSON object instead, so you need to typecast to TJSONObject.

Try this instead:

procedure TCLOSINGForm.SpeedButton10Click(Sender: TObject);
var
  JsonValue: TJSONValue;
  JsonObject: TJSONObject;
  Branch, st: string;
begin
  st := '{iWN5p2qfRFeGKXn1m3iGnDW0Vkl2: {"PROFILE":{"BIRTHDAY":"8\/20\/19","FULL NAME":"","GENDER":"MALE","NATIONALITY":"INDONESIA","NICK NAME":"","OFFICE":"CLOSING SYSTEM","PHONE NO":"","REFERAL UID":"","WEDDING":"8\/20\/19"}}}';
  JsonValue := TJSONObject.ParseJSONValue(st);
  if JsonValue <> nil then
  try
    JsonObject := JsonValue as TJSONObject;
    JsonObject := JsonObject.GetValue('iWN5p2qfRFeGKXn1m3iGnDW0Vkl2') as TJSONObject;
    JsonObject := JsonObject.GetValue('PROFILE') as TJSONObject;

    Branch := JsonObject.GetValue('BIRTHDAY').Value;
    mem.Lines.Add('Parsed BIRTHDAY ' + Branch);

    Branch := JsonObject.GetValue('FULL NAME').Value;
    mem.Lines.Add('Parsed FULL NAME ' + Branch);
  finally
    JsonValue.Free;
  end;
end;

 

Edited by Remy Lebeau

Share this post


Link to post

This may be coded in a more short form using 10.3.2. First case:

var
  JsonValue: TJSONValue;
  Branch: string;
begin
  JsonValue := TJSONObject.ParseJSONValue(st, False, True);
  try
    Branch := JsonValue.GetValue<string>('data.conditions[0].temp');
    memo1.Lines.add('Parsed temperature '+branch);

    Branch := JsonValue.GetValue<string>('data.conditions[2].bar_sea_level');
    memo1.Lines.add('Parsed barometer '+branch);
  finally
    JsonValue.Free;
  end;
end;

Second case:

var
  JsonValue: TJSONValue;
  Branch: string;
begin
  JsonValue := TJSONObject.ParseJSONValue(st, False, True);
  try
    Branch := JsonValue.GetValue<string>('iWN5p2qfRFeGKXn1m3iGnDW0Vkl2.PROFILE.BIRTHDAY');
    memo1.Lines.Add('Parsed BIRTHDAY ' + Branch);

    Branch := JsonValue.GetValue<string>('iWN5p2qfRFeGKXn1m3iGnDW0Vkl2.PROFILE.FULL NAME');
    memo1.Lines.Add('Parsed FULL NAME ' + Branch);
  finally
    JsonValue.Free;
  end;
end;

This is most simple code. Although not fastest, but may be enough fast. Depending on the requirements it may be optimized.

  • Like 1
  • Thanks 1

Share this post


Link to post
On 8/22/2019 at 6:39 AM, Remy Lebeau said:

That is because there are two problems in your code:

  1. the JSON string you are passing in to ParseJSONValue() does not represent a JSON object, just a single JSON name/value pair, so your first typecast to TJSONObject will fail.  You need to wrap the entire JSON string in angle brackets, since ParseJSONValue() can't return a TJSONPair.
  2. The "PROFILE" field is not a JSON array, so your typecast to TJSONArray will fail.  The "PROFILE" field is a JSON object instead, so you need to typecast to TJSONObject.

Try this instead:


procedure TCLOSINGForm.SpeedButton10Click(Sender: TObject);
var
  JsonValue: TJSONValue;
  JsonObject: TJSONObject;
  Branch, st: string;
begin
  st := '{iWN5p2qfRFeGKXn1m3iGnDW0Vkl2: {"PROFILE":{"BIRTHDAY":"8\/20\/19","FULL NAME":"","GENDER":"MALE","NATIONALITY":"INDONESIA","NICK NAME":"","OFFICE":"CLOSING SYSTEM","PHONE NO":"","REFERAL UID":"","WEDDING":"8\/20\/19"}}}';
  JsonValue := TJSONObject.ParseJSONValue(st);
  if JsonValue <> nil then
  try
    JsonObject := JsonValue as TJSONObject;
    JsonObject := JsonObject.GetValue('iWN5p2qfRFeGKXn1m3iGnDW0Vkl2') as TJSONObject;
    JsonObject := JsonObject.GetValue('PROFILE') as TJSONObject;

    Branch := JsonObject.GetValue('BIRTHDAY').Value;
    mem.Lines.Add('Parsed BIRTHDAY ' + Branch);

    Branch := JsonObject.GetValue('FULL NAME').Value;
    mem.Lines.Add('Parsed FULL NAME ' + Branch);
  finally
    JsonValue.Free;
  end;
end;

Hello @Remy Lebeau, just curious, is TJSONObject.Create not required or this is just optional and you'll just have to make sure the JSON object is freed? 

 

Share this post


Link to post
On 1/17/2021 at 9:13 PM, misc_bb said:

just curious, is TJSONObject.Create not required

No, it is not, as the code in question is not creating any new JSON objects, only reading them.  The framework will do all of the necessary creations for you while parsing the JSON string.

On 1/17/2021 at 9:13 PM, misc_bb said:

or this is just optional

It is not necessary in this example at all.  If you were creating a new JSON document, THEN you would have to create new objects as needed.

On 1/17/2021 at 9:13 PM, misc_bb said:

and you'll just have to make sure the JSON object is freed?

Only the root object returned by ParseJSONValue() needs to be freed explicitly.  The rest of the objects in the document are owned by the root object and will be freed automatically when the root object is freed.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×