I am looking to extract certain values from a JSON path of arrays and objects and use these values for further processing and am struggling with accessing those elements. Here is the JSON response:
[
{
"od_pair":"7015400:8727100",
"buckets":[
{
"bucket":"C00",
"original":2,
"available":2
},
{
"bucket":"A01",
"original":76,
"available":0
},
{
"bucket":"B01",
"original":672,
"available":480
}
]
},
{
"od_pair":"7015400:8814001",
"buckets":[
{
"bucket":"C00",
"original":2,
"available":2
},
{
"bucket":"A01",
"original":40,
"available":40
},
{
"bucket":"B01",
"original":672,
"available":672
},
{
"bucket":"B03",
"original":632,
"available":632
},
{
"bucket":"B05",
"original":558,
"available":558
}
]
}
]
I tried accessing the root elements with $ but I could not get further with it.
Here is the test method that I have written. I want to extract the value for od_pair and within each od_pair, I need to be able to retrieve the bucket codes and their available numbers.
public static void updateBuckets(String ServiceName, String DateOfJourney) throws Exception {
File jsonExample = new File(System.getProperty("user.dir"), "\\LogAvResponse\\LogAvResponse.json");
JsonPath jsonPath = new JsonPath(jsonExample);
List<Object> LegList = jsonPath.getList("$");
// List<HashMap<String, String>> jsonObjectsInArray = jsonPath.getList("$");
int NoofLegs = LegList.size();
System.out.println("No of legs :" + NoofLegs);
for (int j = 0; j <= NoofLegs; j++)
// for (HashMap<String, String> jsonObject : jsonObjectsInArray) {
{
String OD_Pair = jsonPath.param("j", j).getString("[j].od_pair");
// String OD_Pair = jsonObject.get("od_pair");
System.out.println("OD Pair: " + OD_Pair);
List<Object> BucketsList = jsonPath.param("j", j).getList("[j].buckets");
int NoOfBuckets = BucketsList.size();
// System.out.println("OD Pair: " + OD_Pair);
System.out.println("no of Buckets: " + NoOfBuckets);
for (int i = 0; i < NoOfBuckets; i++) {
String BucketCode = jsonPath.param("j", j).param("i", i).getString("[j].buckets[i].bucket");
String Available = jsonPath.param("j", j).param("i", i).getString("[j].buckets[i].available");
int BucketCodeColumn = XLUtils.getBucketCodeColumn(BucketCode);
int ServiceRow = XLUtils.getServiceRow(ServiceName, DateOfJourney, OD_Pair);
System.out.println("Row of " + ServiceName + ":" + DateOfJourney + "is:" + ServiceRow);
System.out.println("Bucket Code column of " + BucketCode + " is: " + BucketCodeColumn);
XLUtils.updateAvailability(ServiceRow, BucketCodeColumn, Available);
}
}
}
}
This is the error I see:
Caused by:
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup
failed:
Script1.groovy: 1: unexpected token: [ @ line 1, column 27.
restAssuredJsonRootObject.[j].od_pair
Can someone help me please?
Looking at the error message, it looks like you are using rest-assured and that the
JsonPath
class isio.restassured.path.json.JsonPath
from the rest-assured library.I'm sure you're aware, but (perhaps for other readers) note that this is different from Jayway's json-path and is NOT the
com.jayway.jsonpath.JsonPath
class from that library.Also be aware that, as mentioned in the documentation rest-assured uses the Groovy GPath syntax for manipulating/extracting JSON.
With that, I believe the following will extract what you need, i.e. od_pair and their corresponding buckets with available numbers:
where for each entry of the map, the key is the od_pair and the value is another map whose key is the bucket and value is the available number. The
jsonString
is the JSON you provided in the question.You can iterate through the map to get what you want:
Printing out the map you will get:
{7015400:8727100={C00=2, A01=0, B01=480}, 7015400:8814001={C00=2, A01=40, B01=672, B03=632, B05=558}}
Printing the map as JSON using Gson:
you will get
For background, the String
collectEntries{entry -> [entry.od_pair, entry.buckets.collectEntries{bucketEntry -> [bucketEntry.bucket, bucketEntry.available]}]}
is a Groovy closure that uses methods from the Groovy Collections API: Refer Collection, List and Map
Shout out to @Fenio for the pure Java solution above.
I would suggest parsing your JSON into Java classes to ease the processing.
How to do that? First, we need to create Java classes which will represent the JSON you provided.
Let's analyze the JSON. Starts with an array. The array contains multiple JSON Object. These objects contain
od_pair
value and array of objects calledbuckets
.Let's create a class (you can name it whatever you want)
Pair
This class represents a single JSON Object in the main Array. It contains
od_pair
value AND nested JSON Array but in Java representation -> List ofBucketObject
classes. Let's createBucketObject
class:We have only 3 values in each of the objects.
Now, it's time to parse JSON into the written classes.
Remember that
Pair
is a single JSON Object. That's why we start parsing from the root represented by dollar sign$
and we declare that JSON should be parsed into an ARRAY ofPair
objects!Now, processing will be much simpler!
I am not sure what do you need, but I will show you an example of how to get data from the buckets based on
od_pair
field and you should be able to figure out the rest of the processing.So, we have the array of Pair class:
Pair[] pairs
;Now, we want to get 1 Pair object based on
od_pair
value.Now, we have the
Pair
object. We can accessbuckets
for this object usingThe rest of the processing is iterating over
List<BucketObject>
and getting desired values.Hope it helps!
OP asked me to advise on how to fix his code, hence the second answer.
Let's analyze the code you provided:
I am not using compilator right now, so I can miss a few things.
#1
First thing I can see is that you save the main array into the
List<Object>
List<Object> LegList = jsonPath.getList("$");
Instead, you could save it to more understandable type, since Object is so generic, you have no idea what's inside it.
List<HashMap<String, Object>> LegList = jsonPath.getList("$");
#2 The
for
loop looks incorrect because of the evaluatorj <= NoofLegs;
. This will probably causeIndexArrayOutOfBoundsException
or something similar. With the given code, if you have 4 legs, thefor
loop will try to process 5 legs which are incorrect.#3 Similar to the #1, line where you save the bucket list
List<Object> BucketsList = jsonPath.param("j", j).getList("[j].buckets");
Could also be changed toList<HashMap<String, Object>>
instead.If you'd do that, you wouldn't need integer-based nested
for
loop.You see, the
HashMap<String, Object>
is actually crucial to parse nested objects. The String is just a name likebuckets
orod_pair
. It's the JSON representation. The second argumentObject
is different. RestAssured returns different types within the HashMap, that's why we useObject
instead ofString
. Sometimes it's not String.Example based on your JSON:
Collect buckets to List of HashMaps:
List<HashMap<String, Object>> bucketsList = jsonPath.param("j", j).getList("[j].buckets");
Each of the HashMap in the list is a representation of this:
The
Object
inHashMap
is eitherString
orInteger
in your case. So, if you get elementbucket
from aHashMap
you'll get its value.Let's combine it with
for
loop for further clarification: