In my dealings with JSON I found that most JSON structures are created as one large object. This means they start with a { bracket and end with a } bracket.
But, I have seen cases where the JSON data itself is an array of objects. This means the data starts with [ and ends with ]. While I've never understood why this was allowed, I'm in no place to question it. But I just feel that it would be just as easy to wrap the entire array in one more object.
Here is some sample JSON data where the data itself is an array of objects:
[
{
"id":352104,
"vin":"123456",
"label":"3070",
"color":"WHITE",
"make":"VOLVO",
"model":"VN",
"deviceSerialNumber":"5010395849",
"year":2005,
"odometer":{
"units":"MILES",
"timestamp":"2014-10-14T18:37:13Z",
"readOnly":"TRUE",
"value":199400.38
},
"engineRunTime":{
"isTracked":"ALWAYS",
"timestamp":"2014-10-14T18:33:49Z",
"readOnly":"TRUE",
"value":"P478DT6H24M0.000S"
},
"licensePlate":{
"state":"FL",
"country":"US"
},
"trackableItemType":"VEHICLE",
"fuelType":"DIESEL",
"createdTimestamp":{
"readOnly":true,
"value":"2013-11-15T16:43:47Z"
},
"modifiedTimestamp":{
"readOnly":true,
"value":"2014-10-10T19:11:50Z"
}
},
{
"id":354261,
"vin":"234567",
"label":"3292",
"color":"WHITE",
"make":"VOLVO",
"model":"VN",
"deviceSerialNumber":"5010411594",
"year":2011,
"odometer":{
"units":"MILES",
"timestamp":"2014-10-14T18:38:14Z",
"readOnly":"TRUE",
"value":366985.99
},
"engineRunTime":{
"isTracked":"ALWAYS",
"timestamp":"2014-10-14T18:18:11Z",
"readOnly":"TRUE",
"value":"P299DT19H0M0.000S"
},
"licensePlate":{
"state":"FL",
"country":"US"
},
"trackableItemType":"VEHICLE",
"fuelType":"DIESEL",
"createdTimestamp":{
"readOnly":true,
"value":"2013-11-22T18:30:51Z"
},
"modifiedTimestamp":{
"readOnly":true,
"value":"2014-10-10T15:22:25Z"
}
},
{
"id":356045,
"vin":"345678",
"label":"401",
"color":"WHITE",
"make":"MACK",
"model":"CH",
"deviceSerialNumber":"5010551993",
"year":2001,
"odometer":{
"units":"MILES",
"timestamp":"2014-06-03T16:56:49Z",
"readOnly":"TRUE",
"value":203119.47
},
"engineRunTime":{
"isTracked":"ALWAYS",
"timestamp":"2014-06-03T15:52:39Z",
"readOnly":"TRUE",
"value":"P229DT1H24M0.000S"
},
"licensePlate":{
"state":"FL",
"country":"US"
},
"trackableItemType":"VEHICLE",
"fuelType":"DIESEL",
"createdTimestamp":{
"readOnly":true,
"value":"2013-12-02T18:19:00Z"
},
"modifiedTimestamp":{
"readOnly":true,
"value":"2014-10-10T17:11:55Z"
}
},
{
"id":352049,
"vin":"456789",
"label":"3035",
"color":"WHITE",
"make":"VOVLO",
"model":"VN430",
"deviceSerialNumber":"5010404824",
"year":2006,
"odometer":{
"units":"MILES",
"timestamp":"2014-10-14T18:38:11Z",
"readOnly":"TRUE",
"value":347126.47
},
"engineRunTime":{
"isTracked":"ALWAYS",
"timestamp":"2014-10-14T18:13:48Z",
"readOnly":"TRUE",
"value":"P623DT6H12M0.000S"
},
"licensePlate":{
"state":"FL",
"country":"US",
"value":"084NLI"
},
"trackableItemType":"VEHICLE",
"fuelType":"DIESEL",
"createdTimestamp":{
"readOnly":true,
"value":"2013-11-15T15:21:15Z"
},
"modifiedTimestamp":{
"readOnly":true,
"value":"2013-11-15T15:21:15Z"
}
},
{
"id":359172,
"vin":"567890",
"label":"3281",
"color":"WHITE",
"make":"VOLVO",
"model":"VN",
"deviceSerialNumber":"5010555410",
"year":2011,
"odometer":{
"units":"MILES",
"timestamp":"2014-10-13T14:58:33Z",
"readOnly":"TRUE",
"value":360237.9
},
"engineRunTime":{
"isTracked":"ALWAYS",
"timestamp":"2014-10-13T12:14:37Z",
"readOnly":"TRUE",
"value":"P316DT7H24M0.000S"
},
"licensePlate":{
"state":"FL",
"country":"US"
},
"trackableItemType":"VEHICLE",
"fuelType":"DIESEL",
"createdTimestamp":{
"readOnly":true,
"value":"2013-12-19T16:15:48Z"
},
"modifiedTimestamp":{
"readOnly":true,
"value":"2014-10-10T15:21:15Z"
}
},
{
"id":361056,
"vin":"678901",
"label":"3272",
"color":"WHITE",
"make":"WHITE",
"model":"VN",
"deviceSerialNumber":"5010587534",
"year":2011,
"odometer":{
"units":"MILES",
"timestamp":"2014-10-10T19:27:39Z",
"readOnly":"TRUE",
"value":528542.0900000001
},
"engineRunTime":{
"isTracked":"ALWAYS",
"timestamp":"2014-10-10T19:25:20Z",
"readOnly":"TRUE",
"value":"P300DT20H12M0.000S"
},
"licensePlate":{
"state":"FL",
"country":"US"
},
"trackableItemType":"VEHICLE",
"fuelType":"DIESEL",
"createdTimestamp":{
"readOnly":true,
"value":"2013-12-31T13:14:03Z"
},
"modifiedTimestamp":{
"readOnly":true,
"value":"2014-10-10T15:18:36Z"
}
}
]
In these special cases the processing of the data is a little different. We put together the following program as an example of processing this type of data:
H DFTACTGRP(*NO) BNDDIR('YAJL')
****************************************************************
* Imports
****************************************************************
/include yajl_h
****************************************************************
* Global Definitions
****************************************************************
D CSTMSTDS E DS EXTNAME(CSTMSTPF)
****************************************************************
* Work Variables
****************************************************************
D docNode s like(yajl_val)
D vehicleList s like(yajl_val)
D node s like(yajl_val)
D subNode s like(yajl_val)
D val s like(yajl_val)
*
D stringValue s 65535a varying
D decValue s 13p 2
D intValue s 10i 0
*
D i s 10i 0
D errMsg s 500a varying inz('')
****************************************************************
/free
docNode = yajl_stmf_load_tree( '/tmp/jsonarray.json' : errMsg );
if errMsg <> '';
// handle error
endif;
exsr $Vehicles;
yajl_tree_free(docNode);
*inlr = *on;
//***************************************************************
//* Process Vehicles
//***************************************************************
begsr $Vehicles;
vehicleList = docNode;
i = 0;
dow YAJL_ARRAY_LOOP(vehicleList:i:node );
val = YAJL_object_find(node:'id');
intValue = yajl_get_number(val);
val = YAJL_object_find(node:'vin');
stringValue = yajl_get_string(val);
subNode = YAJL_object_find(node:'odometer');
val = YAJL_object_find(subNode:'units');
stringValue = yajl_get_string(val);
val = YAJL_object_find(subNode:'value');
decValue = yajl_get_number(val);
subNode = YAJL_object_find(node:'engineRunTime');
val = YAJL_object_find(subNode:'value');
stringValue = yajl_get_string(val);
enddo;
endsr;
The first thing you'll probably notice is that to begin processing after loading the document we set the vehicleList pointer to the docNode pointer. Why? Well, because the entire set of JSON data itself is an array.
Once this is done we're able to use the YAJL_ARRAY_LOOP() function as before to process each item in the array.
Another difference in this example is that some of the item descriptions are objects themselves.
Take a look at the odometer object:
"odometer":{
"units":"MILES",
"timestamp":"2014-10-14T18:37:13Z",
"readOnly":"TRUE",
"value":199400.38
}
In order to process this we will need to get a pointer to the odometer object. Luckily, we can find this just as easily as finding basic data. We just use that pointer then to get values for each of the subfields:
subNode = YAJL_object_find(node:'odometer');
val = YAJL_object_find(subNode:'units');
stringValue = yajl_get_string(val);
val = YAJL_object_find(subNode:'value');
decValue = yajl_get_number(val);
So, first we find the odometer object using the YAJL_object_find() procedure. But, in this case we are saving the location in a pointer named subNode. This pointer then points to the odometer object and we are able to retrieve the data items for this object.
We perform a similar action for retrieving the engineRunTime data.
Again, it isn't that difficult as long as you can keep track of what is pointing to what.
Related Articles:
I tried using this example in a program but I can't seem to get it to work.
This is the JSON file
[{"serviceName":"USPS Priority Mail - Package","serviceCode":"usps_priority_mail","shipmentCost":8.7200,"otherCost":0.0},
{"serviceName":"USPS Priority Mail - Medium Flat Rate Box","serviceCode":"usps_priority_mail","shipmentCost":13.7500,"otherCost":0.0},
{"serviceName":"USPS Priority Mail - Small Flat Rate Box","serviceCode":"usps_priority_mail","shipmentCost":7.9000,"otherCost":0.0},
{"serviceName":"USPS Priority Mail - Large Flat Rate Box","serviceCode":"usps_priority_mail","shipmentCost":19.3000,"otherCost":0.0},
{"serviceName":"USPS Priority Mail - Flat Rate Envelope","serviceCode":"usps_priority_mail","shipmentCost":7.4000,"otherCost":0.0},
{"serviceName":"USPS Priority Mail - Flat Rate Padded Envelope","serviceCode":"usps_priority_mail","shipmentCost":8.0000,"otherCost":0.0},
{"serviceName":"USPS Priority Mail - Regional Rate Box A","serviceCode":"usps_priority_mail","shipmentCost":8.3400,"otherCost":0.0},
{"serviceName":"USPS Priority Mail - Regional Rate Box B","serviceCode":"usps_priority_mail","shipmentCost":9.5600,"otherCost":0.0},
{"serviceName":"USPS Priority Mail - Legal Flat Rate Envelope","serviceCode":"usps_priority_mail","shipmentCost":7.7000,"otherCost":0.0},
{"serviceName":"USPS Parcel Select Ground - Package","serviceCode":"usps_parcel_select","shipmentCost":8.4700,"otherCost":0.0}]
This is my code:
D docNode s like(yajl_val)
D list s like(yajl_val)
D node s like(yajl_val)
D val s like(yajl_val)
D stringValue s 500A varying
D decValue4 s 13P 4
D decValue2 s 13P 2
list = docNode;
// read results file
i = 0;
dow YAJL_ARRAY_LOOP( list: i: node );
val = YAJL_object_find(node: 'serviceName');
stringValue = yajl_get_string(val);
sern14 = stringValue;
val = YAJL_object_find(node: 'serviceCode');
stringValue = yajl_get_string(val);
serc14 = stringValue;
val = YAJL_object_find(node: 'shipmentCost');
decValue4 = yajl_get_number(val);
cost14 = decValue4;
val = YAJL_object_find(node: 'otherCost');
decValue2 = yajl_get_number(val);
cost14 =+ decValue2;
What am I missing?
Thanks for your help
Nancy
I don't see where you're loading the JSON and setting docNode.
That was it. I knew I had missed something but couldn't see it.
Thanks
Nancy
If you have an array in the array which node should you use to read the child array and how do you get it?
I like to create a new node for each array, especially in those cases.
arrayOne = YAJL_object_find(docNode:'arrayOne');
i = 0;
dow YAJL_ARRAY_LOOP(arrayOne:i:node1);
arrayTwo = YAJL_object_find(node1:'arrayTwo');
j = 0;
dow YAJL_ARRAY_LOOP(arrayTwo:j:node2);
..process array using node2
enddo;
enddo;
Thanks I would look into it.