mewindy 0 Posted May 10, 2019 (edited) 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 May 10, 2019 by mewindy Share this post Link to post
Remy Lebeau 1392 Posted May 10, 2019 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
mewindy 0 Posted May 11, 2019 (edited) 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 May 11, 2019 by mewindy Share this post Link to post
Remy Lebeau 1392 Posted May 11, 2019 (edited) 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 May 11, 2019 by Remy Lebeau 2 Share this post Link to post
mewindy 0 Posted May 11, 2019 OMG you are correct! I should have spotted that its working now thanks Remy! Share this post Link to post
Lars Fosdal 1792 Posted May 21, 2019 https://jsonlint.com is very handy. Share this post Link to post
Lie Ming 0 Posted August 21, 2019 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
Remy Lebeau 1392 Posted August 21, 2019 (edited) 11 hours ago, Lie Ming said: but it won't work...please need help/. That is because there are two problems in your code: 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. 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 August 21, 2019 by Remy Lebeau Share this post Link to post
Dmitry Arefiev 101 Posted October 17, 2019 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. 1 1 Share this post Link to post
misc_bb 7 Posted January 18, 2021 On 8/22/2019 at 6:39 AM, Remy Lebeau said: That is because there are two problems in your code: 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. 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
Remy Lebeau 1392 Posted January 19, 2021 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