Delphi / SuperObject - Accessing Subnodes - json

I have the following JSON from my server:
{
"userid":"12",
"username":"TestChar",
"logged":"yes",
"status":"Premium User",
"areas":{
"SERVICEAREA_XX1":{
"id":"1",
"area":"SERVICEAREA_XX1",
"version":"3000",
"usr_group":"0"
},
"SERVICEAREA_XX2":{
"id":"2",
"area":"SERVICEAREA_XX2",
"version":"31000",
"usr_group":"0"
},
"SERVICEAREA_XX3":{
"id":"3",
"area":"SERVICEAREA_XX3",
"version":"2000",
"usr_group":"1"
}
}
}
With SuperObjects i can get the count of "SERVICEAREA"'s with
ob['areas'].AsObject.count
How can i now get access to the elements of the different "SERVICEAREA"'s?
Thanks for your help...

you can access elements of an array using a for ... in loop:
var
item: ISuperObject;
begin
for item in ob['areas'] do ...
or without an enumerator, using a 'normal' for loop:
var
idx: Integer;
item: ISuperObject;
begin
for idx := 0 to ob['areas'].AsArray.Length - 1 do
item := ob['areas'].AsArray[idx];

Marjan has the answer for you. Here is a little more information how to access the item properties with an example:
var
item: ISuperObject;
...
for item in ob['areas'] do
begin
WriteLn(item['id'].AsInteger);
WriteLn(item['area'].AsString);
WriteLn(item['version'].AsInteger);
end;

use this code If you want to access key/value(like Javascriptfor..in)
if ObjectFindFirst(JsonData, ite) then
with JsonData.AsObject do
repeat
PutO(ite.key, ite.val.Clone);
until not ObjectFindNext(ite);
ObjectFindClose(ite);

Related

Iterating over a list in JSON using TypeScript

I'm having a problem iterating over my json in TypeScript. I'm having trouble with one specific json field, the tribe. For some reason I can't iterate over that one. In the debugger, I'm expecting the Orc to show up but instead I get a 0. Why is this? How do I iterate correctly over my tribe data?
// Maps a profession or tribe group name to a bucket of characters
let professionMap = new Map<string, Character[]>()
let tribeMap = new Map<string, Character[]>()
let herolistJson = require('./data/HeroList.json')
for (let hero of herolistJson){
// Certain characters can have more than one tribe
// !!!!! The trouble begins here, tribe is 0???
for (let tribe in hero.tribe){
let tribeBucket = tribeMap.get(tribe) as Character[]
// If the hero does not already exist in this tribe bucket, add it
if(tribeBucket.find(x => x.name == hero.name) === undefined )
{
tribeBucket.push(new Character(hero.name, hero.tribe, hero.profession, hero.cost))
}
}
}
My json file looks like this
[
{
"name": "Axe",
"tribe": ["Orc"],
"profession": "Warrior",
"cost": 1
},
{
"name": "Enchantress",
"tribe": ["Beast"],
"profession": "Druid",
"cost": 1
}
]
in iterates over the keys of an object, not the values. The keys of an array are its indices. If you use of instead, you'll use the newer iterator protocol and an Array's iterator provides values instead of keys.
for (let tribe of /* in */ hero.tribe) {
Note, that this won't work in IE 11, but will work in most other browsers as well many JS environments that are ES2015 compatible. kangax/compat has a partial list.
Change the "in" to "of" in second loop.

How to get odata.nextLink from the returned JSON object using oracle's apex_json

I am retrieving data from an odata service. The response contains a link for loading more data i.e. odata.nextLink which I need to retrieve to load more data. How do I do this using oracle's apex_json?
The server's response is something like this:
{
"odata.metadata":"http://localhost:60497/odata/$metadata#tables","value":[
{"id":001,"name":"abc" }
.
.
],
"odata.nextLink":"http://localhost:60497/odata/tables?$skip=10"
}
Normally I would parse the data and then retrieve the information like this next_link := apex_json.get_varchar2('odata.nextLink'); but since it contains a point that won't work.
In this case:
apex_json.get_varchar2('odata.nextLink');
it is considering nextLink as the value of odata.
DECLARE
v_json APEX_JSON.T_VALUES;
v_str_json VARCHAR2(4000);
next_link VARCHAR2(4000);
BEGIN
v_str_json := '{
"odata" : {"nextLink" : "mylink"},
"odata.metadata":"http://localhost:60497/odata/$metadata#tables","value":[
{"id":001,"name":"abc" }
],
"odata.nextLink":"http://localhost:60497/odata/tables?$skip=10"
}
}';
APEX_JSON.PARSE(v_json, v_str_json);
next_link := APEX_JSON.GET_VARCHAR2(p_path => 'odata.nextLink', p_values => v_json);
dbms_output.put_line(next_link);
END;
>> OUTPUT: mylink
I do not know how to say "odata.nextLink" to be interpreted literally; and not as a path.
If nobody knows:
1 - or stop sending "odata." at the beginning of the name of each attribute;
2 - or use replace to remove.

Extract specific values from JSON array

I have a JSON response that is formatted this way:
- Client 1
- Date: 15.07.2017
- Name: John
- URL: www.google.com
- Client 2
- Date: 15.07.2017
- Name: Jane
- URL: www.google.com
- Client N...
How could I extract only the Name & URL value from each client so I could add them to a listbox for example? Also please note that "Client 1" could be named otherwise, like "User 1" or just "1", that's not important, but the code should extract the values regardless of the parent object name.
PS: Sorry for missleading, the JSON format above was pseudo-code from memory, the actual format is:
[
{
"date":"xxx",
"name":"xxx",
"url":"xxx"
},
{
"date":"xxx",
"name":"xxx",
"url":"xxx"
},
{
"date":"xxx",
"name":"xxx",
"url":"xxx"
}
]
Answer in case anybody is looking.
procedure Answer;
var
JSON: string;
ClientItem: TJSONValue;
ClientList: TJSONArray;
ListBoxItem: TListBoxItem;
begin
JSON := TFile.ReadAllText('.\your-file.json');
ClientList := TJSONObject.ParseJSONValue(JSON) as TJSONArray;
if Assigned(ClientList) then
try
ListBox.Items.BeginUpdate;
try
for ClientItem in ClientList do
begin
ListBoxItem := TListBoxItem.Create(ListBox);
ListBoxItem.StyleLookup := 'CustomListbox';
ListBoxItem.StylesData['URL'] := ClientItem.GetValue<string>('url');
ListBoxItem.StylesData['Name'] := ClientItem.GetValue<string>('name');
Listbox.AddObject(ListBoxItem);
end;
finally
Listbox.Items.EndUpdate;
end;
finally
ClientList.Free;
end;
end;

Delphi / SuperObject - Accessing subnodes away returning NIL

I have the following JSON from server:
{
"SuccessResponse": {
"Head": {
"RequestId": "",
"RequestAction": "GetMultipleOrderItems",
"ResponseType": "Orders",
"Timestamp": "2016-05-10T15:13:06-0300"
},
"Body": {
"Orders": {
"Order": [
{
"OrderId": "457634",
"OrderNumber": "256176682",
"OrderItems": {
"OrderItem": {
"OrderItemId": "712893",
"ShopId": "14690930",
"OrderId": "457634",
...
I'm using the following code to access this values:
procedure TForm1.GetOrdersPendingItems;
var
mydata : string;
obj, orderObj: ISuperObject;
orderArray: TSuperArray;
begin
mydata := GetURLAsString(GenerateApiUrl('GetMultipleOrderItems', 'OrderIdList', '[457634,457817]'));
obj := SO(mydata);
orderObj := obj['SuccessResponse.Body.Orders.Order'];
end;
With this code, if I use a simple Label1.Caption := orderObj.AsString;, it show me this:
"OrderId": "457634",
"OrderNumber": "256176682",
"OrderItems": {
"OrderItem": {
"OrderItemId": "712893",
"ShopId": "14690930",
"OrderId": "457634",
...
By the logic, the values inner of OrderItem can be access like this: orderObj['OrderItems.OrderItem'];, but if I try to access a "easy" value like OrderId, that is the first element, using orderObj['OrderId']; it returns nil and the same happens with all nodes of the orderObj...
So, the values in the orderObj.AsString can't be accessed to convert into variable...
There are a way to access the value inner of OrderItem? My objective is convert the values of OrderItem into a ClientDataSet using the following code:
orderArray := orderObj.AsArray;
TJSONDB.JsonToClientDataSet(orderArray, cdsOrdersItems);
Thanks!
Here you mention this:
By the logic, the values inner of OrderItem can be access like this: orderObj['OrderItems.OrderItem'];
This would work, indeed.But right after you wrote this contradicting the last sentence:
but if I try to access a "easy" value like OrderId, that is the first element, using orderObj['OrderId'];
By the logic, as you say, to access the values you could do:
orderObj['OrderItems.OrderItem.OrderId'];
and not orderObj['OrderId']; directly.

PL/JSON Message Lists

I working on parsing a json string stored in a table CLOB in oracle 11g. This process is part of a long parsing routine that parses the data and stores the values in another table and I've just noticed that part of my data is not getting out. The json parses and validates with JSONLint. So I've simplified the parsing to try and find out where I'm going wrong.
So my json coming out my table looks like this.
{
"JSON_data": {
"plant_id": "3006",
"transmit_time": "2015-12-18 11:57:45",
"messages": [{
"work_msg": {
"msg_time": "2015-06-23 04:54:17",
"trigger_type": "interval",
"vert_correction": 358.3,
"ch_latitude": 37.916302,
"ch_longitude": -87.487365,
"ch_heading": 212.3,
"ch_cable_port": 1029.79,
"ch_cable_stbd": 348.63,
"ch_depth": -27.03,
"slurry_velocity": 25.71,
"slurry_density": 1.02,
"ch_rpm": 205.49,
"ch_psi": 540.89,
"prod_instantaneous": 0,
"prod_cumulative": 1216.100000,
"outfall_latitude": 37.915967,
"outfall_longitude": -87.484369,
"outfall_heading": 120.7,
"pump_entries": [{
"pump_name": "main",
"vacuum": 12.73,
"outlet_psi": 22.88
}],
"spud_entries": [{
"position": 6
}]
},
"pipe_length_event": {
"msg_time": "2015-06-23 04:54:17",
"length_floating": 970
}
}]
}
}
My parsing is correctly finding and doing its thing with the 'work_msg' data. It's the 'pipe_length_event' data that I'm not getting to. Below is my simplified pl/sql procedure.
DECLARE
vCONTENT CLOB;
v_parent_json json;
v_json_message_list json_list;
v_json_message_list_value json_value;
v_parent_json_value json_value;
BEGIN
SELECT CONTENT INTO vCONTENT FROM SJM_TEMP4;
v_parent_json := json(vCONTENT);
v_parent_json := json(v_parent_json.get(1));
v_json_message_list := json_list(v_parent_json.get('messages'));
DBMS_OUTPUT.PUT_LINE(v_json_message_list.count);
for message_loop_counter in 1 ..v_json_message_list.count loop
v_parent_json_value := json(v_json_message_list.get(message_loop_counter)).get(1);
DBMS_OUTPUT.PUT_LINE(v_parent_json_value.mapname);
END LOOP;
END;
My dbms_output first gives me a sub-list count of 1. Not 2 so my parsing is not even recognizing the "pipe_length_event" as a sub-list of "messages".
How do I get "pipe_length_event" data using this procedure? I'm almost certain this was working in the past so my first thought is that the json is formatted differently. Is the json ill-formatted?
Thanks in advance.
FOUND IT!!
The issue is in fact the JSON formatting. Below is the correct format. The "work_msg" list was not closed so "pipe_length_event" list was not recognized.
{
"JSON_data": {
"plant_id": "3006",
"transmit_time": "2015-12-18 11:57:45",
"messages": [{
"work_msg": {
"msg_time": "2015-06-23 04:54:17",
"trigger_type": "interval",
"vert_correction": 358.3,
"ch_latitude": 37.916302,
"ch_longitude": -87.487365,
"ch_heading": 212.3,
"ch_cable_port": 1029.79,
"ch_cable_stbd": 348.63,
"ch_depth": -27.03,
"slurry_velocity": 25.71,
"slurry_density": 1.02,
"ch_rpm": 205.49,
"ch_psi": 540.89,
"prod_instantaneous": 0,
"prod_cumulative": 1216.100000,
"outfall_latitude": 37.915967,
"outfall_longitude": -87.484369,
"outfall_heading": 120.7,
"pump_entries": [{
"pump_name": "main",
"vacuum": 12.73,
"outlet_psi": 22.88
}],
"spud_entries": [{
"position": 6
}]
}
}, {
"pipe_length_event": {
"msg_time": "2015-06-23 04:54:17",
"length_floating": 970
}
}]
}
}