Reputation: 3923
I am trying to take an XML file and convert it into a JSON document using Groovy, specifically with XmlSlurper and JsonBuilder. I can do this fairly easily if I hard code everything, but I'd rather not do that if possible.
Here is a sample of the XML - in real life the structure is the same, but there are hundreds of nodes.
<root>
<data>
<node1>
<child1>1</child1>
<child2>2</child2>
<child3>3</child3>
</node1>
<node2>
<child1>1</child1>
<child2>2</child2>
<child3>3</child3>
</node2>
</data>
</root>
I'd like to map this to the following JSON:
{
"type": "test",
"time": {
"$date": timestamp
},
"data": {
"node1": {
"child1": 1,
"child2": 2,
"child3": 3
},
"node2": {
"child1": 1,
"child2": 2,
"child3": 3
}
}
}
My current code looks like this (thanks to @dmahapatro):
def parser = new XmlSlurper().parse("file.xml")
def getNode = {String parentNode, String childNode ->
parser.data."$parentNode"
."$childNode"
.find { it.name() == childNode }
}
def root = json {
type "test"
time { $date timestamp }
data {
node1 {
child1 getNode("node1","child1").toInteger()
child2 getNode("node1","child2").toInteger()
child3 getNode("node1","child3").toInteger()
}
node2 {
child1 getNode("node1","child1").toInteger()
child2 getNode("node1","child2").toInteger()
child3 getNode("node1","child3").toInteger()
}
}
}
What I'd like to do is loop through the XML and dynamically create the nodes in the JSON document. Considering that I have hundreds of nodes to deal with in real life hard coding these all into the JsonBuilder isn't really ideal. I've tried doing the following, but it is not working. Hopefully it will give you an idea of the direction I am trying to go with this:
def json = new JsonBuilder()
def root = json {
type "test"
time { $date timestamp }
data {
parser.data.childNodes().each {
it.name {
it.childNodes().each {
it.name it.text()
}
}
}
}
}
Upvotes: 1
Views: 8937
Reputation: 50285
How about this? :) This is where I had my last line in the previous question.
def xml='''
<root>
<data>
<node1>
<child1>1</child1>
<child2>2</child2>
<child3>3</child3>
</node1>
<node2>
<child1>1</child1>
<child2>2</child2>
<child3>3</child3>
</node2>
</data>
</root>
'''
def slurper = new XmlSlurper().parseText(xml)
def builder = new groovy.json.JsonBuilder()
builder {
type 'record'
time { $date 'timestamp' }
data {
slurper.data.childNodes().each { nodeElem ->
"$nodeElem.name" {
nodeElem.childNodes().each { childElem ->
"$childElem.name" childElem.text().toInteger()
}
}
}
}
}
builder.toPrettyString()
If there will be cases where the child elements value is not an integer, then below can be used instead:
childElem.text().isNumber() ? childElem.text().toInteger() : childElem.text()
Forgot to mention the main point why your approach is not working. it
is the implicit variable for the immediate wrapped closure. In your case you have 3 closures and it
is used every where. Name them as shown above.
Upvotes: 2