Reputation: 360
I would like to parse the below nested JSON in Groovy and get the values of "it","ft","stg","prd" for each application and store in separate array.Can someone help please ?
{
"Application1": {
"environments": {
"it": [
"server1"
],
"ft": [
"server2"
],
"stg": [
"server3"
],
"prd": [
"server4"
]
},
"war-path" : "/opt/tomcat/",
"war-name" : "Application1"
},
"Application2": {
"environments": {
"it": [
"serverA"
],
"ft": [
"serverB"
],
"stg": [
"serverC"
],
"prd": [
"serverD"
]
},
"war-path" : "/var/lib",
"war-name" : "Application2"
}
}
}
Expected output something like below in separate list for each environment. Also the 1st level(Application1,Application2..) will be dynamic always
it = [server1,serverA]
ft = [server2,serverB]
stg = [server3, serverC]
prd = [server4,serverD]
Updated: After deriving expected answer with the inputs from Philip Wrage.
def projects = readJSON file: "${env.WORKSPACE}//${infrafile}"
def json_str = JsonOutput.toJson(projects)
def json_beauty = JsonOutput.prettyPrint(json_str)
def envlist = ["it","ft","stg","prd"]
def fileListResult = []
for (envname in envlist) {
servers=serverlist(json_beauty,envname)
println(servers)
}
def serverlist(json_beauty,envname){
def jsonSlurper = new JsonSlurper()
def jsonMap = jsonSlurper.parseText(json_beauty)
assert jsonMap instanceof Map
jsonMap.each { appName, appDetails ->
assert appDetails instanceof Map
appDetails.environments.each { envName, servers ->
for (items in servers{
if (envName == "${envname}"){
fileListResult.add(items)
}
}
}
}
return fileListResult
}
Upvotes: 1
Views: 8321
Reputation: 1559
As suggested by @Chris, you can use the built-in JsonSlurper
to parse the JSON and then navigate the parsed results as a Map
.
In the following example I show how you can simply print the results to the console. However, using this as a guide, you can see how to extract the data into whatever kind of data structure that suits your purpose.
Assume that you have the JSON in a String
variable jsonText
. You may be pulling in from a file or an HTTP POST or whatever your app requires. I used the following code to set this value for testing.
def jsonText = """
{
"Application1": {
"environments": {
"it": [
"server1"
],
"ft": [
"server2"
],
"stg": [
"server3"
],
"prd": [
"server4"
]
},
"war-path" : "/opt/tomcat/",
"war-name" : "Application1"
},
"Application2": {
"environments": {
"it": [
"serverA"
],
"ft": [
"serverB"
],
"stg": [
"serverC"
],
"prd": [
"serverD"
]
},
"war-path" : "/var/lib",
"war-name" : "Application2"
}
}
"""
The meat of the solution then follows. Parse the JSON text into a Map
, and then iterate over the entries in that Map
, performing whatever operations you require. The servers for each environment will already be contained within a List
.
import groovy.json.JsonSlurper
def jsonSlurper = new JsonSlurper()
def jsonMap = jsonSlurper.parseText(jsonText)
assert jsonMap instanceof Map
jsonMap.each { appName, appDetails ->
println "Application: $appName"
assert appDetails instanceof Map
appDetails.environments.each { envName, servers ->
assert servers instanceof List
println "\tEnvironment: $envName"
println "\t\t$servers"
}
}
From this code I obtain the following console output.
Application: Application1
Environment: it
[server1]
Environment: ft
[server2]
Environment: stg
[server3]
Environment: prd
[server4]
Application: Application2
Environment: it
[serverA]
Environment: ft
[serverB]
Environment: stg
[serverC]
Environment: prd
[serverD]
EDIT (based on clarification of required output):
import groovy.json.JsonSlurper
def jsonText = "\n{\n \"Application1\": {\n \"environments\": {\n \"it\": [\n \"server1\"\n ],\n \"ft\": [\n \"server2\"\n ],\n \"stg\": [\n \"server3\"\n ],\n \"prd\": [\n \"server4\"\n ]\n },\n \"war-path\" : \"/opt/tomcat/\",\n \"war-name\" : \"Application1\"\n},\n \"Application2\": {\n \"environments\": {\n \"it\": [\n \"serverA\"\n ],\n \"ft\": [\n \"serverB\"\n ],\n \"stg\": [\n \"serverC\"\n ],\n \"prd\": [\n \"serverD\"\n ]\n },\n \"war-path\" : \"/var/lib\",\n \"war-name\" : \"Application2\"\n}\n}\n"
def jsonSlurper = new JsonSlurper()
def jsonMap = jsonSlurper.parseText(jsonText)
def result = [:]
jsonMap.each { appName, appDetails ->
appDetails.environments.each { envName, servers ->
if ( !result.containsKey(envName) ) {
result.put(envName, [])
}
result.get(envName).addAll(servers)
}
}
println result
Results are a Map
where the keys are the various environments specified within JSON file, and the values are List
s of servers associated with those environments across all applications. You can access any List
individually with something like result.stg
, or assign these the different variables later if that's desired/required (def stg = result.stg
).
[it:[server1, serverA], ft:[server2, serverB], stg:[server3, serverC], prd:[server4, serverD]]
Upvotes: 3
Reputation: 37008
If you want all environments
, you can use the spread operator to take
all environments from the values. Next you have to merge the maps on
the keys. E.g.
def json = """ { "Application1": { "environments": { "it": [ "server1" ], "ft": [ "server2" ], "stg": [ "server3" ], "prd": [ "server4" ] }, }, "Application2": { "environments": { "it": [ "serverA" ], "ft": [ "serverB" ], "stg": [ "serverC" ], "prd": [ "serverD" ] }, } } }"""
def data = new groovy.json.JsonSlurper().parseText(json)
println data.values()*.environments.inject{ a, b ->
b.inject(a.withDefault{[]}) { m, kv ->
// with groovy 2.5+: m.tap{ get(kv.key).addAll(kv.value) }
m[kv.key].addAll(kv.value); m
}
}
// → [it:[server1, serverA], ft:[server2, serverB], stg:[server3, serverC], prd:[server4, serverD]]
Upvotes: 0