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

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"
}
]
}

Related

Preparing JSON array of Objects from multiple array list

I am very new to the Groovy scripts and would like to build a JSON output from the below JSON input. Kindly help!
My JSON input looks like this:
{
"id":"1222",
"storageNode": {
"uuid": "22255566336",
"properties": {
"BuinessUnit": [
"Light",
"Fan",
"Watch"
],
"Contact": [
"abc#gmail.com",
"fhh#gmail.com"
],
"Location": [
"Banglore",
"Surat",
"Pune"
]
}
}
}
Expected Output:
[
{
"BuinessUnit": "Light",
"Contact": "abc#gmail.com",
"Location": "Banglore"
},
{
"BuinessUnit": "Fan",
"Contact": "fhh#gmail.com",
"Location": "Surat"
},
{
"BuinessUnit": "Watch",
"Contact": "",
"Location": "Pune"
}
]
Please note that in case any array is not matching the value count that will always be the last one and in that case, a blank value ("") has to be populated. The "BusinessUnit" object can be referred for array size validation.
My code looks like this:
import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;
import groovy.json.*;
def Message processData(Message message) {
//Body
def body = message.getBody(String.class);
def jsonSlurper = new JsonSlurper()
def list = jsonSlurper.parseText(body)
String temp
def BU = list.storageNode.properties.get("BusinessUnit")
def builder = new JsonBuilder(
BU.collect {
[
BusinessUnit: it
]
}
)
message.setBody(builder.toPrettyString())
return message
}
It is only returning this:
[
{
"BusinessUnit": "Light"
},
{
"BusinessUnit": "Fan"
},
{
"BusinessUnit": "Watch"
}
]
Now how will I add other parts to it? Please help!
I have come up with the following solution that converts source JSON string to the target JSON string:
import groovy.json.JsonBuilder
import groovy.json.JsonSlurper
def json = '''
{
"id":"1222",
"storageNode": {
"uuid": "22255566336",
"properties": {
"BusinessUnit": [
"Light",
"Fan",
"Watch"
],
"Contact": [
"abc#gmail.com",
"fhh#gmail.com"
],
"Location": [
"Banglore",
"Surat",
"Pune"
]
}
}
}
'''
println convert(json)
String convert(String json) {
def list = new JsonSlurper().parseText(json)
List<String> units = list.storageNode.properties.BusinessUnit
List<String> contacts = list.storageNode.properties.Contact
List<String> locations = list.storageNode.properties.Location
def result = []
units.eachWithIndex { unit, int index ->
result << [
BusinessUnit: unit,
Contact : contacts.size() > index ? contacts[index] : '',
Location : locations.size() > index ? locations[index] : '',
]
}
return new JsonBuilder(result).toPrettyString()
}
I've omitted the logic of getting string from the message and packaging transformed JSON into message.
I hope it will help you to move forward. Please let me know if you need further assistance here.
You can use the built-in Groovy facilities, like transpose():
import groovy.json.*
def json = new JsonSlurper().parseText '''{ "id":"1222", "storageNode": { "uuid": "22255566336", "properties": {
"BuinessUnit": [ "Light", "Fan", "Watch" ],
"Contact": [ "abc#gmail.com", "fhh#gmail.com" ],
"Location": [ "Banglore", "Surat", "Pune" ] } } }'''
def names = json.storageNode.properties*.key
def values = json.storageNode.properties*.value
int maxSize = values*.size().max()
// pad lists with trainiling spaces
values.each{ v -> ( maxSize - v.size() ).times{ v << '' } }
def result = values.transpose().collect{ tuple -> [ names, tuple ].transpose().collectEntries{ it } }
assert result.toString() == '[[BuinessUnit:Light, Contact:abc#gmail.com, Location:Banglore], [BuinessUnit:Fan, Contact:fhh#gmail.com, Location:Surat], [BuinessUnit:Watch, Contact:, Location:Pune]]'
This piece of code can process everything under storageNode.properties.

Save result to a new csv file instead of println Groovy

How can I save result of groovy script to a new file? C:/temp/all1.csv. I want to parse json file to csv, script is working fine but I don't know how can I save result in a new file. Please help.
import groovy.json.*
import java.io.File
def json ='''
{
"expand": "schema,names",
"startAt": 0,
"maxResults": 50,
"total": 21,
"issues": [
{
"expand": "operations,versionedRepresentations",
"id": "217580",
"self": "issue/217580",
"key": "ART-4070",
"fields": {"summary": "#[ART] Pre.3 Verification \\"S\\""}
},
{
"expand": "operations,versionedRepresentations",
"id": "217579",
"self": "issue/217579",
"key": "ART-4069",
"fields": {"summary": "Verification \\"C\\""}
},
{
"expand": "operations,versionedRepresentations",
"id": "217577",
"self": "issue/217577",
"key": "ART-4068",
"fields": {"summary": "#[ART] Enum type"}
}
]
}
'''
File csvFile = new File( 'C:/temp/all1.csv')
def jsonSlurper = new JsonSlurper()
def config = [ // header -> extractor
"key": { it.key },
"summary": { it.fields.summary }
]
def encode(e) { // help with nulls; quote the separator
(e ?: "").replaceAll(";", "\\;")
}
def csvLine(items) { // write items as "CSV"
println(items.collect{ encode it }.join(";"))
}
def obj = new JsonSlurper().parseText(json)
csvLine(config.keySet())
obj.issues.each{ issue ->
csvLine(config.values().collect{ f -> f issue })
}
result:
key;summary
ART-4070;#[ART] Pre.3 Verification "S"
ART-4069;Verification "C"
ART-4068;#[ART] Enum type
To go with the current code, you could use csvFile.append(...) instead of println inside your
csvLine function and depending on your amount of real data, this might
be a good compromise between performance and resource.
Or you can write the whole CSV at once. E.g.
// prepare whole table
def data = [config.keySet()]
data.addAll(
obj.issues.collect{ issue ->
config.values().collect{ f -> f issue }
}
)
// write table as csv
def csvFile = "/tmp/out.csv" as File
csvFile.text = data.collect{
it.collect{ encode it }.join(";")9
}.join("\n")

How to compare 2 CSV files with only first 6 signs in groovy

Please help with parse CSV to JSON from 2 files in groovy. I have 1st CSV like this (line numbers may be different each time):
testKey,status
Name001-something,PASS
Name002-something,PASS
Name003-something,FAIL
CSV2 (list of all testkeys but with different names of keys:
Kt,Pd
PT-01,Name007-something1
PT-02,Name001-something2
PT-03,Name003-something3
PT-05,Name002-something5
PT-06,Name004-something5
PT-07,Name006-something5
This code is parsing only the same value but I need also testKey even when first 7 signs are the same in both files. Maybe substring(0,6)?
import groovy.json.*
def csv1 = '''
testKey,status
Name001-something,PASS
Name002-something,PASS
Name003-something,FAIL
Name004-something,FAIL
'''.trim()
def csv2 = '''
Kt,Pd
PT-01,Name007-something1
PT-02,Name001-something2
PT-03,Name003-something3
PT-05,Name002-something4
PT-06,Name004-something5
PT-07,Name006-something6
'''.trim()
boolean skip1st = false
def testMap2 = [:]
//parse and bind 1st CSV to Map
csv2.splitEachLine( /\s*,\s*/ ){
skip1st ? ( testMap2[ it[ 1 ] ] = it[ 0 ] ) : ( skip1st = true )
}
def keys
def testList = []
csv1.splitEachLine( /\s*,\s*/ ){ parts ->
if( !keys )
keys = parts*.trim()
else{
def test = [:]
parts.eachWithIndex{ val, ix -> test[ keys[ ix ] ] = val }
//check if testKey present in csv2
if( testMap2[ test.testKey ] ){
test.testKey = testMap2[ test.testKey ] // replace values from CSV2
testList << test
}
}
}
def builder = new JsonBuilder()
def root = builder {
testExecutionKey 'DEMO-303'
info user: 'admin'
tests testList
}
builder.toPrettyString()
result is:
{
"testExecutionKey": "DEMO-303",
"info": {
"user": "admin"
},
"tests": [
]
}
In a result I need something like:
{
"testExecutionKey": "DEMO-303",
"info": {
"user": "admin"
},
"tests": [
{
"testKey": "PT-02",
"status": "PASS"
},
{
"testKey": "PT-05",
"status": "PASS"
},
{
"testKey": "PT-03",
"status": "FAIL"
},
{
"testKey": "PT-06",
"status": "FAIL"
}
]
}

Can I combine Json.Builder with JsonOutput in groovy? CSV to JSON

I have to parse csv file (with some modifications) to json in groovy.When I'm trying to execute this code i have a problem with spliting some values.
Content of csv file:
TestKey;Finished;user;status
RWS.PT.001;2020-07-20T23:01:21+02:00;admin;PASS;
RWS.PT.002;2020-07-20T23:02:21+02:00;admin;PASS;
my code in groovy:
import groovy.json.*
def builder = new groovy.json.JsonBuilder()
def root = builder {
testExecutionKey 'DEMO-303'
info (
user: 'admin')
tests 'rows':'ghgh','uuuuu'
}
print JsonOutput.prettyPrint(JsonOutput.toJson(root))
def csvfile = new File('C:/temp/raportTest.csv').readLines()
def keys = csvfile[0].split(';')
def rows = csvfile[1..-1].collect { line ->
def i = 0, vals = line.split(';')
keys.inject([:]) { map, key -> map << ["$key": vals[i++]] }
}
print JsonOutput.prettyPrint(JsonOutput.toJson(rows))
my target file should looks like this:
{
"testExecutionKey": "DEMO-303",
"info" : {
"user" : "admin"
},
"tests" : [
{
"testKey" : "RWS.PT.001",
"finished" : "2020-07-20T23:01:21+02:00",
"status" : "PASS"
},
{
"testKey" : "RWS.PT.002",
"finished" : "2020-07-20T23:01:21+02:00",
"status" : "PASS"
}
]
}
Now I have:
{
"testExecutionKey": "DEMO-303",
"info": {
"user": "admin"
},
"tests": [
{
"rows": "ghgh"
},
"uuuuu"
]
}[
{
"TestKey": "RWS.PT.001",
"Finished": "2020-07-20T23:01:21+02:00",
"user": "admin",
"status": "PASS"
},
{
"TestKey": "RWS.PT.002",
"Finished": "2020-07-20T23:02:21+02:00",
"user": "admin",
"status": "PASS"
}
]
How can I input code from def rows (from JsonOutput) into JsonBuilder (instead of "rows": "ghgh").
Please help!
You over-engineered it a bit. You actually don't have to combine anything, just use the JsonBuilder and some Groovy magic:
import groovy.json.*
def kindaFile = '''
TestKey;Finished;user;status
RWS.PT.001;2020-07-20T23:01:21+02:00;admin;PASS;
RWS.PT.002;2020-07-20T23:02:21+02:00;admin;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))
prints
{
"testExecutionKey": "DEMO-303",
"info": {
"user": "admin"
},
"tests": [
{
"TestKey": "RWS.PT.001",
"Finished": "2020-07-20T23:01:21+02:00",
"user": "admin",
"status": "PASS"
},
{
"TestKey": "RWS.PT.002",
"Finished": "2020-07-20T23:02:21+02:00",
"user": "admin",
"status": "PASS"
}
]
}

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()