Collect list of attributes with groovy and jsonslurper into single list - json

What's the best way to collect a list of attributes from a JSON hierarchy? Here's what I'm trying to do:
import groovy.json.JsonSlurper
def jsontxt = '''
{
"lvl1": [
{
"lvl2": [
{
"lvl3": [
{
"a1": false,
"a2": {
"a2b1": false,
"a2b2": false
},
"a3": "wantvalue1"
},
{
"a1": false,
"a2": {
"a2b1": false,
"a2b2": false
},
"a3": "wantvalue2"
}
],
},
],
}
]
}
'''
def jsresult = new JsonSlurper().parseText(jsontxt)
def mytry = jsresult.lvl1.lvl2.lvl3.collect{it.a3} // [[[wantvalue1, wantvalue2]]]
assert ["wantvalue1","wantvalue2"] == mytry
Apologies the input is not as clean as it could be but I didn't want to lose my situation.
What I want is a basic list without the additional empty lists. I know there must be a really cool way to do this but I'm not groovy enough for it. . . help??

Pretty close. Try flatten().
Try jsresult.lvl1.lvl2.lvl3.collect{it.a3}.flatten() or myTry.flatten()

Related

How to get the All index values in Groovy JSON xpath

Please find the attached Groovy code which I am using to get the particular filed from the response body.
Query 1 :
It is retrieving the results when the I am using the correct Index value like if the data.RenewalDetails[o], will give output as Value 1 and if the data.RenewalDetails[1], output as Value 2.
But in my real case, I will never know about number of blocks in the response, so I want to get all the values that are satisficing the condition, I tried data.RenewalDetails[*] but it is not working. Can you please help ?
Query 2:
Apart from the above condition, I want to add one more filter, where "FamilyCode": "PREMIUM" in the Itemdetails, Can you help on the same ?
def BoundId = new groovy.json.JsonSlurper().parseText('{"data":{"RenewalDetails":[{"ExpiryDetails":{"duration":"xxxxx","destination":"LHR","from":"AUH","value":2,"segments":[{"valudeid":"xxx-xx6262-xxxyyy-1111-11-11-1111"}]},"Itemdetails":[{"BoundId":"Value1","isexpired":true,"FamilyCode":"PREMIUM","availabilityDetails":[{"travelID":"AAA-AB1234-AAABBB-2022-11-10-1111","quota":"X","scale":"XXX","class":"X"}]}]},{"ExpiryDetails":{"duration":"xxxxx","destination":"LHR","from":"AUH","value":2,"segments":[{"valudeid":"xxx-xx6262-xxxyyy-1111-11-11-1111"}]},"Itemdetails":[{"BoundId":"Value2","isexpired":true,"FamilyCode":"PREMIUM","availabilityDetails":[{"travelID":"AAA-AB1234-AAABBB-2022-11-10-1111","quota":"X","scale":"XXX","class":"X"}]}]}]},"warnings":[{"code":"xxxx","detail":"xxxxxxxx","title":"xxxxxxxx"}]}')
.data.RenewalDetails[0].Itemdetails.find { itemDetail ->
itemDetail.availabilityDetails[0].travelID.length() == 33
}?.BoundId
println "Hello " + BoundId
Something like this:
def txt = '''\
{
"data": {
"RenewalDetails": [
{
"ExpiryDetails": {
"duration": "xxxxx",
"destination": "LHR",
"from": "AUH",
"value": 2,
"segments": [
{
"valudeid": "xxx-xx6262-xxxyyy-1111-11-11-1111"
}
]
},
"Itemdetails": [
{
"BoundId": "Value1",
"isexpired": true,
"FamilyCode": "PREMIUM",
"availabilityDetails": [
{
"travelID": "AAA-AB1234-AAABBB-2022-11-10-1111",
"quota": "X",
"scale": "XXX",
"class": "X"
}
]
}
]
},
{
"ExpiryDetails": {
"duration": "xxxxx",
"destination": "LHR",
"from": "AUH",
"value": 2,
"segments": [
{
"valudeid": "xxx-xx6262-xxxyyy-1111-11-11-1111"
}
]
},
"Itemdetails": [
{
"BoundId": "Value2",
"isexpired": true,
"FamilyCode": "PREMIUM",
"availabilityDetails": [
{
"travelID": "AAA-AB1234-AAABBB-2022-11-10-1111",
"quota": "X",
"scale": "XXX",
"class": "X"
}
]
}
]
}
]
},
"warnings": [
{
"code": "xxxx",
"detail": "xxxxxxxx",
"title": "xxxxxxxx"
}
]
}'''
def json = new groovy.json.JsonSlurper().parseText txt
List<String> BoundIds = json.data.RenewalDetails.Itemdetails*.find { itemDetail ->
itemDetail.availabilityDetails[0].travelID.size() == 33 && itemDetail.FamilyCode == 'PREMIUM'
}?.BoundId
assert BoundIds.toString() == '[Value1, Value2]'
Note, that you will get the BoundIds as a List
If you amend your code like this:
def json = new groovy.json.JsonSlurper().parse(prev.getResponseData()
you would be able to access the number of returned items as:
def size = json.data.RenewalDetails.size()
as RenewalDetails represents a List
Just add as many queries you want using Groovy's && operator:
find { itemDetail ->
itemDetail.availabilityDetails[0].travelID.length() == 33 &&
itemDetail.FamilyCode.equals('PREMIUM')
}
More information:
Apache Groovy - Parsing and producing JSON
Apache Groovy: What Is Groovy Used For?

pyjq - how to use "select" with both query and value as variables

I am writing a code in python3 where i am struggling with usage of variables with "pyjq", the code works without variables but variables are not getting parsed inside pyjq.
The documentation referred is https://github.com/doloopwhile/pyjq/blob/master/README.md#api
Please check the code given below and suggest -
My code
import json, os
import pyjq
from flask import Flask, request, jsonify
def query_records():
args = {"meta.antivirus.enabled": "true"}
for key, value in args.items():
with open('/tmp/data.txt', 'r') as f:
print (key)
print (value)
data = f.read()
records = json.loads(data)
query = ("." + key)
print (query)
#jq '.[]|select(.meta.antivirus.enabled=="true")' filename.json works,issue with variable substitution in python
match = pyjq.all('.[]|select(["$query"]==$value)', records, vars={"value": value,"query": query})
print (match)
query_records()
Content of file "/tmp/data.txt"
[
{
"name": "alpharetta",
"meta": {
"antivirus": {
"enabled": "true"
},
"limits": {
"cpu": {
"enabled": "true",
"value": "250m"
}
}
}
},
{
"meta": {
"allergens": {
"eggs": "true",
"nuts": "false",
"seafood": "false"
},
"calories": 230,
"carbohydrates": {
"dietary-fiber": "4g",
"sugars": "1g"
},
"fats": {
"saturated-fat": "0g",
"trans-fat": "1g"
}
},
"name": "sandwich-nutrition"
},
{
"meta": {
"allergens": {
"eggs": "true",
"nuts": "false",
"seafood": "true"
},
"calories": 440,
"carbohydrates": {
"dietary-fiber": "4g",
"sugars": "2g"
},
"fats": {
"saturated-fat": "0g",
"trans-fat": "1g"
}
},
"name": "random-nutrition"
}
]
Expected output(which works without variables)
{
"name": "alpharetta",
"meta": {
"antivirus": {
"enabled": "true"
},
"limits": {
"cpu": {
"enabled": "true",
"value": "250m"
}
}
}
}
Current output []
seems like some issue with variables not being passed in case of "query" , help would be appreciated.
Edit 1
It works if I hardcode "query" -
match = pyjq.all('.[]|select(.meta.antivirus.enabled==$value)', records, vars={"value": value,"query": query})
but not vice-versa
which probably narrows it down to issue with the variable "query"
JQ is not a necessity and I can use other libraries too,given that json is returned
Variables are intended to be used for values, not for jq expressions (at least not directly).
I think the easiest option here is to go for an fstring:
match = pyjq.all(f'.[]|select({query}==$value)', records, vars={"value": value})
and it probably makes sense to prepend the period inside the fstring:
match = pyjq.all(f'.[]|select(.{key}==$value)', records, vars={"value": value})

Python3 JSON parse with duplicate keys

Sorry for the newbie question, there is a json response like this;
import json
jsonObj = json.loads("""
{
"data": [
{
"name_space": "name",
"value": "Angelina"
},
{
"name_space": "surname",
"value": "Jolie"
},
{
"name_space": "year",
"value": "1975"
}
]
}
""")
and I am currently able to parsing this way
for meta in jsonObj['data']:
if meta['name_space'] == 'name':
print(meta['value'])
if meta['name_space'] == 'surname':
print(meta['value'])
if meta['name_space'] == 'year':
print(meta['value'])
I'm researching if there are different ways to do this and make the code look cleaner or simpler.
clean_dict = {x['name_space']: x['value'] for x in jsonObj['data']} would give you the following dict:
{'name': 'Angelina', 'surname': 'Jolie', 'year': '1975'}
That code uses the x['name_space'] value as your new keys in the dict.
Then you should be able to print it however you'd like, such as print(clean_dict.values()).

Obtaining the child values randomly in JSON

I have a JSON like below: I need to extract the Options -> Child as a Random and also Values within the options as randomly. How can we achieve in jmeter ?
{
"id":37,
"merchant_id":"39",
"title":"Parker Pens",
"subtitle":null,
"price":1000,
"description":null,
"images":[ ],
"image_thumbs":[ ],
"options":[
{
"code":"color",
"label":"Color",
"extra_info":"",
"values":[
{ },
{ },
{ }
]
},
{
"code":"size",
"label":"Size",
"extra_info":"",
"values":[
{ },
{ },
{ }
]
}
],"options_available":[
{ },
{ },
{ },
{ },
{ },
{ },
{ },
{ },
{ }
], "custom_options":[
]
}
I have to fetch the child of options randomly . In that i have to fetch the value of "Code" and its associated value within the "Value" .
Help is appreciated and useful
Your requirements are a little bit vague as you haven't indicated what is the desired output format. One of the solutions would be using JSR223 PostProcessor in order to obtain the random value from random options array like:
import com.jayway.jsonpath.JsonPath
import org.apache.commons.lang3.RandomUtils
import org.apache.jmeter.samplers.SampleResult
def options = JsonPath.read(prev.getResponseDataAsString(), '$.options')
def randomOption = options.get(RandomUtils.nextInt(0, options.size()))
def values = randomOption.get('values')
def randomValue = values.get(RandomUtils.nextInt(0, values.size())) as String
vars.put('randomValue', randomValue)
References:
Jayway JsonPath - A Java DSL for reading JSON documents
Apache Groovy - Why and How You Should Use It
Apache Groovy - Parsing and Producing JSON

Can we create JSON using JsonBuilder for the following JSON?

I want to create the below JSON using JsonBuilder.
"isOut": false,
"baleRun": {
"incData": true,
"appendCricket": [{
"min": 10,
"max": 32,
"price": "10"
}]
}
I have tried below code to create it:-
import groovy.json.*
def builder = new JsonBuilder()
def root = builder.baleRun{
incData true
builder.appendCricket [
{
min 10
max 32
price "10000"
}
]
}
Getting below error:-
groovy.lang.MissingPropertyException: No such property: appendCricket for
class: groovy.json.JsonBuilder error.
Any idea how to produce this?
The simplest way is to build a Map for the data you want, then pass this to the builder in the constructor:
import groovy.json.*
def data = [
isOut: false,
baleRun: [
incData: true,
appendCricket: [
[min: 10, max: 32, price: '10']
]
]
]
def json = new JsonBuilder(data).toString()
It is easy to create it using map, like #tim_yates suggested.
Of course, it is also possible to create the way you started with. Should be taken care for array, see in line:
def json = new groovy.json.JsonBuilder()
json {
isOut false
baleRun {
incData true
appendCricket( [
{
min 10
max 32
price "10000"
}
])
}
}
println json.toPrettyString()
Quickly try the same online demo