Converting XML to JSON in Groovy Converting XML to JSON in Groovy json json

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!