JSON and XML are the de facto data interchange standard formats used by industry applications. The two formats share many similarities, but have different goals in their design. JSON is designed to be a data exchange language, which is human readable and easy for computers to parse and use. XML also shares the readability goal, but suffers from a higher degree of verbosity and complexity.
Nevertheless, the two formats are here to stay, and a case for converting from one format to the other is recurring in the IT industry.
This recipe shows how to convert a JSON document into XML using a Groovy only solution as well as introducing a less "groovier" solution in the There's more... section.
The JSON document to convert is the ui.json
file that we already encountered in the Parsing JSON messages with JsonSlurper recipe.
The conversion is based on groovy.xml.MarkupBuilder
, which allows full control on the final output but makes the code more verbose because we have to explicitly specify all the transformation rules.
ui.json
file is in the same folder as the Groovy script:import groovy.json.JsonSlurper import groovy.xml.MarkupBuilder def reader = new FileReader('ui.json') def ui = new JsonSlurper().parse(reader) def writer = new StringWriter() def xml = new MarkupBuilder(writer)
xml.items { ui.items.each { widget -> item(type: widget.type, height: widget.height, width: widget.width) { axes { widget.axes.each { widgetAxis -> axis(type: widgetAxis.type, name: widgetAxis.title) } } } } } println writer.toString()
<items> <item type='chart' height='270' width='319'> <axes> <axis type='Time' name='Time' /> <axis type='Numeric' name='Profit in EUR' /> </axes> </item> </items>
The code in step 2 is really a testament to the sheer efficiency of builders (see the Defining data structures as code in Groovy recipe in Chapter 3, Using Groovy Language Features). The variable xml
is used to construct the XML element names and attributes that are extracted, via dynamic methods, from the ui
variable, created by the MarkupBuilder
. More information on MarkupBuilder
can be found in the Constructing XML content recipe in Chapter 5, Working with XML in Groovy.
To avoid confusing the Groovy compiler, when we are inside the iterator closures (for example, widget.axes.each { widgetAxis -> ...
) we have to use variable names that are different from the XML element names (for example, axis(type: widgetAxis.type ...
).
The second approach mentioned in this recipe's introduction is to use a third-party library, such as JSON-lib to perform the transformation with little coding. The following code makes use of the XMLSerializer
class to transform the JSON data to XML.
@Grapes([ @Grab(group='net.sf.json-lib', module='json-lib', version='2.3', classifier='jdk15'), @Grab('xom:xom:1.2.5') ]) import net.sf.json.JSONObject import net.sf.json.xml.XMLSerializer def object = JSONObject.fromObject(new File('ui.json').text) println new XMLSerializer().write(object)
Here we trade lines of code for lack of control above the produced XML, that is not quite as readable as the Groovy only example:
<?xml version="1.0" encoding="UTF-8"?> <o> <items class="array"> <e class="object"> <animate type="boolean">true</animate> <axes class="array"> <e class="object"> <fields class="array"> <e type="string">x</e> </fields> <position type="string">left</position> <title type="string">Time</title> <type type="string">Time</type> </e> ... </axes> ... </e> ... </items> </o>
The output can still be tweaked by setting different options of the XmlSerializer
class, but you would not be able to fully control the complete structure of the output. The technique outlined here may be established for very complex JSON documents, which would require a non-trivial amount of code to perform the conversion to XML. An additional approach could be to apply XSLT transformation to the result produced by the XmlSerializer
, but describing the process goes beyond the scope of this recipe.
3.15.239.214