Converting XML to JSON in Groovy
You can do it all with basic Groovy:
// Given an XML stringdef xml = '''<root> | <node>Tim</node> | <node>Tom</node> |</root>'''.stripMargin()// Parse itdef parsed = new XmlParser().parseText( xml )// Convert it to a Map containing a List of Mapsdef jsonObject = [ root: parsed.node.collect { [ node: it.text() ]} ]// And dump it as Jsondef json = new groovy.json.JsonBuilder( jsonObject )// Check it's what we expectedassert json.toString() == '{"root":[{"node":"Tim"},{"node":"Tom"}]}'
HOWEVER, you really need to think about certain things...
- How are you going to represent Attributes?
- Will your XML contain
<node>text<another>woo</another>text</node>
style markup? If so, how are you going to handle that? - CDATA? Comments? etc?
It's not a smooth 1:1 mapping between the two... But for a given specific format of XML, it may be possible to come up with a given specific format of Json.
Update:
To get the names from the document (see comment), you can do:
def jsonObject = [ (parsed.name()): parsed.collect { [ (it.name()): it.text() ]} ]
Update 2
You can add support for greater depth with:
// Given an XML stringdef xml = '''<root> | <node>Tim</node> | <node>Tom</node> | <node> | <anotherNode>another</anotherNode> | </node> |</root>'''.stripMargin()// Parse itdef parsed = new XmlParser().parseText( xml )// Deal with each node:def handlehandle = { node -> if( node instanceof String ) { node } else { [ (node.name()): node.collect( handle ) ] }}// Convert it to a Map containing a List of Mapsdef jsonObject = [ (parsed.name()): parsed.collect { node -> [ (node.name()): node.collect( handle ) ]} ]// And dump it as Jsondef json = new groovy.json.JsonBuilder( jsonObject )// Check it's what we expectedassert json.toString() == '{"root":[{"node":["Tim"]},{"node":["Tom"]},{"node":[{"anotherNode":["another"]}]}]}'
Again, all the previous warnings still hold true (but should be heard a little louder at this point) ;-)
This would do the job: http://www.json.org/java/
At the time of writing this answer, the jar is available on: http://mvnrepository.com/artifact/org.json/json/20140107
The following shows the usage.
Imports:
import org.json.JSONObjectimport org.json.XML
Conversion:
static String convert(final String input) { int textIndent = 2 JSONObject xmlJSONObj = XML.toJSONObject(input) xmlJSONObj.toString(textIndent)}
Related Spock tests to show certain scenarios that we need to watch out for:
void "If tag and content are available, the content is put into a content attribute"() { given: String xml1 = ''' <tag attr1="value"> hello </tag> ''' and: String xml2 = ''' <tag attr1="value" content="hello"></tag> ''' and: String xml3 = ''' <tag attr1="value" content="hello" /> ''' and: String json = ''' {"tag": { "content": "hello", "attr1": "value" }} ''' expect: StringUtils.deleteWhitespace(convert(xml1)) == StringUtils.deleteWhitespace(json) StringUtils.deleteWhitespace(convert(xml2)) == StringUtils.deleteWhitespace(json) StringUtils.deleteWhitespace(convert(xml3)) == StringUtils.deleteWhitespace(json)}void "The content attribute would be merged with the content as an array"() { given: String xml = ''' <tag content="same as putting into the content" attr1="value"> hello </tag> ''' and: String json = ''' {"tag": { "content": [ "same as putting into the content", "hello" ], "attr1": "value" }} ''' expect: StringUtils.deleteWhitespace(convert(xml)) == StringUtils.deleteWhitespace(json)}void "If no additional attributes, the content attribute would be omitted, and it creates array in array instead"() { given: String xml = ''' <tag content="same as putting into the content" > hello </tag> ''' and: String notExpected = ''' {"tag": {[ "same as putting into the content", "hello" ]} } ''' String json = ''' {"tag": [[ "same as putting into the content", "hello" ]] } ''' expect: StringUtils.deleteWhitespace(convert(xml)) != StringUtils.deleteWhitespace(notExpected) StringUtils.deleteWhitespace(convert(xml)) == StringUtils.deleteWhitespace(json)}
Hope this helps anyone who still need to resolve this problem.
I'm a bit late to the party, but the following code will convert any XML into a consistent JSON format:
def toJsonBuilder(xml){ def pojo = build(new XmlParser().parseText(xml)) new groovy.json.JsonBuilder(pojo)}def build(node){ if (node instanceof String){ return // ignore strings... } def map = ['name': node.name()] if (!node.attributes().isEmpty()) { map.put('attributes', node.attributes().collectEntries{it}) } if (!node.children().isEmpty() && !(node.children().get(0) instanceof String)) { map.put('children', node.children().collect{build(it)}.findAll{it != null}) } else if (node.text() != ''){ map.put('value', node.text()) } map}toJsonBuilder(xml1).toPrettyString()
Converts the XML...
<root> <node>Tim</node> <node>Tom</node></root>
Into...
{ "name": "root", "children": [ { "name": "node", "value": "Tim" }, { "name": "node", "value": "Tom" } ]}
Feedback/improvements welcome!