groovy json builder json.call - to combine single Json output - json

I have two ArrayList and I need to print in JSON format. I used the below code to print the ArrayList as JSON string
def a = ['R1','R2']
def b = ['R3','R4']
def json = new groovy.json.JsonBuilder()
json set1: a
println groovy.json.JsonOutput.prettyPrint(json.toString())
json set2: b
println groovy.json.JsonOutput.prettyPrint(json.toString())
Actual output
{
"set1": [
"R1",
"R2"
]
}
{
"set2": [
"R3",
"R4"
]
}
It will be printed as two JSON files, but do I need to print/combine all two sets into a single JSON output?
My expected Output
{
"set1": [
"R1",
"R2"
],
"set2": [
"R3",
"R4"
]
}

def a=[111,222,333]
def b=[444,555,666]
def jb = new groovy.json.JsonBuilder()
jb {
set1(a)
set2(b)
}
println jb.toPrettyString()
Or
println new groovy.json.JsonBuilder([ set1:a, set2:b ]).toPrettyString()

Related

Modifying JSON in Groovy (or JOLT)

I've a simple JSON look like:
{
"account_login" : "google#gmail.com",
"view_id" : 1868715,
"join_id" : "utm_campaign=toyota&utm_content=multiformat_sites&utm_medium=cpc&utm_source=facebook",
"start_date" : "2020-02-03",
"end_date" : "2020-08-30"
}
With following Groovy script (from this answer):
def content = """
{
"account_login" : "google#gmail.com",
"view_id" : 1868715,
"join_id" : "utm_campaign=toyota&utm_content=multiformat_sites&utm_medium=cpc&utm_source=facebook",
"start_date" : "2020-02-03",
"end_date" : "2020-08-30"
}
"""
def slurped = new JsonSlurper().parseText(content)
def builder = new JsonBuilder(slurped)
builder.content.join_id = builder.content.join_id.split("\\s*&\\s*") //# to array
.collectEntries{
//# convert each item to map entry
String[] utmMarks = it.trim().split("\\s*=\\s*")
utmMarks[0] = [
"utm_medium" : "ga:medium",
"utm_campaign" : "ga:campaign",
"utm_source" : "ga:source",
"utm_content" : "ga:adContent",
"utm_term" : "ga:keyword",
].get( utmMarks[0] )
utmMarks
}
.findAll{
k,v-> k && v!=null //# filter out empty/null keys
}
//builder.content.filters = ...
println(builder.toPrettyString())
I'll get:
{
"account_login": "google#gmail.com",
"view_id": 1868715,
"join_id": {
"ga:campaign": "toyota",
"ga:adContent": "multiformat_sites",
"ga:medium": "cpc",
"ga:source": "facebook"
},
"start_date": "2020-02-03",
"end_date": "2020-08-30"
}
I want to update this script (or write new) and add new property: array filters to modified json above. Expected output:
{
"account_login":"google#gmail.com",
"view_id":1868715,
"join_id":{
"ga:campaign":"toyota",
"ga:adContent":"multiformat_sites",
"ga:medium":"cpc",
"ga:source":"facebook"
},
"start_date":"2020-02-03",
"end_date":"2020-08-30",
"converted_utm_marks":"ga:campaign=toyota&ga:adContent=multiformat_sites&ga:medium=cpc&ga:source=facebook",
"filters":[
{
"dimensionName":"ga:medium",
"operator":"EXACT",
"expressions":[
"cpc"
]
},
{
"dimensionName":"ga:adContent",
"operator":"EXACT",
"expressions":[
"multiformat_sites"
]
},
{
"dimensionName":"ga:campaign",
"operator":"EXACT",
"expressions":[
"toyota"
]
},
{
"dimensionName":"ga:source",
"operator":"EXACT",
"expressions":[
"facebook"
]
}
]
}
But the problem is that the set of filters for each JSON will be different. This set depends directly on the join_id set. If JSON join_id will contain:
"join_id": {
"ga:campaign": "toyota",
"ga:keyword": "car"
}
filters array should be:
[
{
"dimensionName":"ga:campaign",
"operator":"EXACT",
"expressions":[
"toyota"
]
},
{
"dimensionName":"ga:keyword",
"operator":"EXACT",
"expressions":[
"car"
]
}
]
operator is always equals EXACT. Property dimensionName - is a join_id.propety name. Expressions is a join_id.property value. So, property filters based on join_id and I need to loop through join_id property and build filters array with described structure. How to achieve expected output? JOLT configuration appreciated also.
I can't even simple iterate through join_id map:
slurped.join_id.each { println "Key: $it.key = Value: $it.value" }
I got the error:
/home/jdoodle.groovy: 24: illegal colon after argument expression;
solution: a complex label expression before a colon must be parenthesized # line 24, column 28.
.collect { [it.ga:campaign] }
UPDATE
I found out how to build this array:
def array =
[
filters: slurped.join_id.collect {key, value ->
[
dimensionName: key,
operator: "EXACT",
expressions: [
value
]
]
}
]
Seems like i got it:
def slurped = new JsonSlurper().parseText(content)
def builder = new JsonBuilder(slurped)
builder.content.filters = builder.content.join_id.collect {key, value ->
[
dimensionName: key,
operator: "EXACT",
expressions: [
value
]
]
}
Are there any better solutions?
def slurped = new JsonSlurper().parseText(content)
def builder = new JsonBuilder(slurped)
builder.content.filters = builder.content.join_id.collect {key, value ->
[
dimensionName: key,
operator: "EXACT",
expressions: [
value
]
]
}

how to parse CSV to JSON from 2 CSV Files in Groovy

Please help with parse CSV to JSON from 2 CSV Files in groovy
For example :
CSV1:
testKey,status
Name001,PASS
Name002,PASS
Name003,FAIL
CSV2:
Kt,Pd
PT-01,Name001
PT-02,Name002
PT-03,Name003
PT-04,Name004
I want to input in "testlist" data from CSV2.val[1..-1],CSV1.val[1..-1]
Result should be like :
{
"testExecutionKey": "DEMO-303",
"info": {
"user": "admin"
},
"tests": [
{
"TestKey": "PT-01",
"status": "PASS"
},
{
"TestKey": "PT-02",
"status": "PASS"
},
{
"TestKey": "PT-03",
"status": "FAIL"
}
]
code without this modification (from only 1 csv):
import groovy.json.*
def kindaFile = '''
TestKey;Finished;user;status
Name001;PASS;
Name002;PASS;
'''.trim()
def keys
def testList = []
//parse CSV
kindaFile.splitEachLine( /;/ ){ parts ->
if( !keys )
keys = parts
else{
def test = [:]
parts.eachWithIndex{ val, ix -> test[ keys[ ix ] ] = val }
testList << test
}
}
def builder = new JsonBuilder()
def root = builder {
testExecutionKey 'DEMO-303'
info user: 'admin'
tests testList
}
println JsonOutput.prettyPrint(JsonOutput.toJson(root))
Your sample JSON doesn't match the CSV definition. It looks lile you're using fields [1..-1] from CSV 1, as you stated, but fields [0..-2] from CSV 2. As you only have 2 fields in each CSV that's the equivalent of csv1[1] and csv2[0]. The example below uses [0..-2]. Note that if you always have exactly two fields in your input files then the following code could be simplified a little. I've given a more generic solution that can cope with more fields.
Load both CSV files into lists
File csv1 = new File( 'one.csv')
File csv2 = new File( 'two.csv')
def lines1 = csv1.readLines()
def lines2 = csv2.readLines()
assert lines1.size() <= lines2.size()
Note the assert. That's there as I noticed you have 4 tests in CSV2 but only 3 in CSV1. To allow the code to work with your sample data, it iterates through through CSV1 and adds the matching data from CSV2.
Get the field names
fieldSep = /,[ ]*/
def fieldNames1 = lines1[0].split( fieldSep )
def fieldNames2 = lines1[0].split( fieldSep )
Build the testList collection
def testList = []
lines1[1..-1].eachWithIndex { csv1Line, lineNo ->
def mappedLine = [:]
def fieldsCsv1 = csv1Line.split( fieldSep )
fieldsCsv1[1..-1].eachWithIndex { value, fldNo ->
String name = fieldNames1[ fldNo + 1 ]
mappedLine[ name ] = value
}
def fieldsCsv2 = lines2[lineNo + 1].split( fieldSep )
fieldsCsv2[0..-2].eachWithIndex { value, fldNo ->
String name = fieldNames2[ fldNo ]
mappedLine[ name ] = value
}
testList << mappedLine
}
Parsing
You can now parse the list of maps with your existing code. I've made a change to the way the JSON string is displayed though.
def builder = new JsonBuilder()
def root = builder {
testExecutionKey 'DEMO-303'
info user: 'admin'
tests testList
}
println builder.toPrettyString()
JSON Output
Running the above code, using your CSV1 and CSV 2 data, gives the JSON that you desire.
for CSV1:
testKey,status
Name001,PASS
Name002,PASS
Name003,FAIL
and CSV2:
Kt,Pd
PT-01,Name007
PT-02,Name001
PT-03,Name003
PT-05,Name002
PT-06,Name004
PT-07,Name006
result is:
{
"testExecutionKey": "DEMO-303",
"info": {
"user": "admin"
},
"tests": [
{
"status": "PASS",
"testKey": "PT-01"
},
{
"status": "PASS",
"testKey": "PT-02"
},
{
"status": "FAIL",
"testKey": "PT-03"
}
]
}
but I need exactly the same values for testKey (testKey from CSV1=Kt from CSV2)
{
"testExecutionKey": "DEMO-303",
"info": {
"user": "admin"
},
"tests": [
{
"testKey": "PT-02",
"status": "PASS"
},
{
"testKey": "PT-05",
"status": "PASS"
},
{
"testKey": "PT-03",
"status": "FAIL"
}
]
}

How to set value of Json inside array

I have the following JSON with in an array and when I try to set a value for this JSON, script passes but value isn't set:
{
"langauageCode": "en-US",
"Test": [{
"_modificationTypeCode": "added",
"allocationTypeCode": "3",
"code": "Test1"
}]
}
My code:
def jsonRequest = slurper.parseText(rawRequest)
def builder = new JsonBuilder(jsonRequest)
builder.content.Test.code[0] ='Test2' //Code value is not getting set to 'Test2'
log.info builder.toPrettyString()
Am I not setting the value correctly?
I assume that slurper is an instance of JsonSlurper. If so, there's no need to use JsonBuilder at all, since sluper returns an instance of a Map. So:
import groovy.json.JsonSlurper
import groovy.json.JsonOutput
def req = '''{
"langauageCode": "en-US",
"Test": [{
"_modificationTypeCode": "added",
"allocationTypeCode": "3",
"code": "Test1"
}]
}'''
def slurped = new JsonSlurper().parseText(req)
slurped.Test[0].code = 'Test2'
println JsonOutput.prettyPrint(JsonOutput.toJson(slurped))

Generate JSON using groovy

I am trying to produce the following JSON structure in Groovy but not getting the output I desire.
{
"settings": [
{
"location": "remote",
"stance": "cold"
},
{
"spareParts": {
"id": "123" {
"info": "In stock"
}
}
}
]
}
First of all, the JSON which is in the question at the moment is invalid. :) Second, since Groovy has great support for this, it doesn't need to be ugly. :)
You can go with closures, maps or combined, see this example: https://github.com/jonatan-ivanov/groovy-training/blob/master/examples/050_JsonBuilder.groovy
Here is an example for your (I think) JSON using maps:
builder = new groovy.json.JsonBuilder(
settings: [
[
location: 'remote',
stance: 'cold'
],
[
spareparts: [
id: '123',
info: 'In stock'
]
]
]
)
println builder.toPrettyString()
And here is its output:
{
"settings": [
{
"location": "remote",
"stance": "cold"
},
{
"spareparts": {
"id": "123",
"info": "In stock"
}
}
]
}
I would use a combination of maps and lists for this. Consider the easier case:
import groovy.json.JsonBuilder
def map = [:]
def map1 = [:]
map1['location'] = 'remote'
def list = []
list << ['id' : '123', 'info' : 'In stock']
map1['spareParts'] = list
map['settings'] = [map1]
def jsonBuilder = new JsonBuilder(map)
println jsonBuilder.toPrettyString()
and then the more complex case (this should be refactored):
import groovy.json.JsonBuilder
def map = [:]
def map1 = [:]
map1['location'] = 'remote'
def list1 = []
list1 << ['id' : '123', 'info' : 'In stock']
map1['spareParts'] = list1
map['settings'] = map1
def map2 = [:]
map2['location'] = 'local'
def list2 = []
list2 << ['id' : '505', 'info' : 'none']
map2['spareParts'] = list2
map['settings'] = [map1, map2]
def jsonBuilder = new JsonBuilder(map)
println jsonBuilder.toPrettyString()

How do I get "keys" from an unkown .json saved in my computer using groovy

My end goal is to parse thru an unknown .json file stored on my laptop and get the key names (not the values only key names) using Groovy in SoapUI.
I want to parse an unknown JSON file stored in my computer and get its keys (name of the keys, not the values). I can do 2 things separately:
I am able to read the local JSON using the following code I found online:
def JSON_URL = "file:///C:/Users/xxx/example.json"
URL url = new URL(JSON_URL)
InputStream urlStream = null
try {
urlStream = url.openStream()
BufferedReader reader = new BufferedReader(new Inpu tStreamReader(urlStream))
JsonSlurper js1 = new JsonSlurper()
Object result = js1.parse(reader)
log.info "==> readJSONfile2 result of read: "+result
} catch (Exception e) {
log.info e
}
And if I have the URL, I am able to parse it and get keys like so:
// getting the response
def resp1 = context.expand('${testStepName#response}')
// parsing the set context
def js1 = new JsonSlurper().parseText(resp1)
def keys = js1.entrySet() as List
log.info "==> runTreatmentPlan keys list is: "+keys
log.info "==> runTreatmentPlan keys size is: "+keys.size()
But I am unable to get the keys if the JSON is local to my machine ie unable to combine both the codes. I get error when I do:
Object result = js1.parseText(reader)
I am new to groovy and SoapUI and json - a total newbie and this is my first question. I am really scared because I have seen that some people are kinda rough towards other newbies if the question is basic. I promise, I did google a lot, and I am sure the experienced people might find my question stupid as well, but I am really stuck. I am unable to combine both pieces of code. I kinda feel that I will some how have to use the response from #1 code, but I don't know how.
Can someone help me please?
==== Updating with the JSON structure:
{
"Key0": [
{
"Key1": "Value1",
"Key2": "Value2",
"Key3": "Value3",
"Key4": {
"subKey1": "subValue1"
},
"Key5": {
"subKey1": "subValue1",
"subKey2": "subValue2",
"subKey3": "subValue3",
"subKey4": "subValue4"
},
"Key6": "2016-07-11T17:52:59.000Z",
"Key7": [
{
"subKey1": "subValue1",
"subKey2": "subValue2"
},
{
"subKey1": "subValue1",
"subKey2": "subValue2"
},
{
"subKey1": "subValue1",
"subKey2": "subValue2"
},
{
"subKey1": "subValue1",
"subKey2": "subValue2"
}
]
},
{
"Key1": "Value1",
"Key2": "Value2",
"Key3": "Value3",
"Key4": {
"subKey1": "subValue1"
},
"Key5": {
"subKey1": "subValue1",
"subKey2": "subValue2",
"subKey3": "subValue3",
"subKey4": "subValue4"
},
"Key6": "2016-07-11T17:52:59.000Z",
"Key7": [
{
"subKey1": "subValue1",
"subKey2": "subValue2"
},
{
"subKey1": "subValue1",
"subKey2": "subValue2"
},
{
"subKey1": "subValue1",
"subKey2": "subValue2"
},
{
"subKey1": "subValue1",
"subKey2": "subValue2"
}
]
}
]
}
Given your input, this code:
import groovy.json.JsonSlurper
def traverse
traverse = { tree, keys = [], prefix = '' ->
switch (tree) {
case Map:
tree.each { k, v ->
def name = prefix ? "${prefix}.${k}" : k
keys << name
traverse(v, keys, name)
}
return keys
case Collection:
tree.eachWithIndex { e, i -> traverse(e, keys, "${prefix}[$i]") }
return keys
default :
return keys
}
}
def content = new JsonSlurper().parse( new File( 'sample.json' ) )
traverse(content).each { println it }
Yields this output:
Key0
Key0[0].Key1
Key0[0].Key2
Key0[0].Key3
Key0[0].Key4
Key0[0].Key4.subKey1
Key0[0].Key5
Key0[0].Key5.subKey1
Key0[0].Key5.subKey2
Key0[0].Key5.subKey3
Key0[0].Key5.subKey4
Key0[0].Key6
Key0[0].Key7
Key0[0].Key7[0].subKey1
Key0[0].Key7[0].subKey2
Key0[0].Key7[1].subKey1
Key0[0].Key7[1].subKey2
Key0[0].Key7[2].subKey1
Key0[0].Key7[2].subKey2
Key0[0].Key7[3].subKey1
Key0[0].Key7[3].subKey2
Key0[1].Key1
Key0[1].Key2
Key0[1].Key3
Key0[1].Key4
Key0[1].Key4.subKey1
Key0[1].Key5
Key0[1].Key5.subKey1
Key0[1].Key5.subKey2
Key0[1].Key5.subKey3
Key0[1].Key5.subKey4
Key0[1].Key6
Key0[1].Key7
Key0[1].Key7[0].subKey1
Key0[1].Key7[0].subKey2
Key0[1].Key7[1].subKey1
Key0[1].Key7[1].subKey2
Key0[1].Key7[2].subKey1
Key0[1].Key7[2].subKey2
Key0[1].Key7[3].subKey1
Key0[1].Key7[3].subKey2
import groovy.json.JsonSlurper
/**
* sample.json present in C:/tools/
* { "foo": "bar", "baz": 123 }
*/
def content = new JsonSlurper().parse( new File( 'C:/tools/sample.json' ) )
assert content.keySet() == ['baz', 'foo'] as Set
UPDATE:
After looking at the actual json structure and the issues with the version of Groovy in SOAPUI, below would be a viable option to get all the keys in a specific format:
import groovy.json.JsonSlurper
def textFromFile = new File('/path/to/example.json').text
def content = new JsonSlurper().parseText(textFromFile)
def getAllKeys(Map item) {
item.collect { k, v ->
v instanceof Map ? convertToString(v).collect { "${k}.$it" } : k
}.flatten()
}
assert getAllKeys(content) == [
'Key1', 'Key2', 'Key3',
'Key4.subKey1', 'Key5.subKey1', 'Key5.subKey2',
'Key5.subKey3', 'Key5.subKey4',
'Key6', 'Key7'
]