Tuesday, August 4, 2009

Pretty Printing Groovy's StreamingMarkupBuilder

Unfortunately, Groovy's StreamingMarkupBuilder will not output indented xml due to its streaming nature. However, never fear, JTidy is here to save the day!

JTidy is a project hosted here on sourceforge and it is a pretty nice HTML/XML pretty printer. It also seems to check your HTML for errors, which is cool! Examples are lacking however so I thought I would share my findings with this example:


public class JTidyExample {

def tidyMeUp(String singleLine) {
StringWriter writer = new StringWriter()
Tidy tidy = new Tidy()
tidy.identity {
setEscapeCdata(false)//leave cdata untouched
setIndentCdata(true)//indent the CData
setXmlTags(true)//working with xml not html
parse(new StringReader(singleLine), writer)
}
writer.toString()
}

def createMarkUp() {
String cData = "<![CDATA[hello]]>"
StreamingMarkupBuilder xml = new StreamingMarkupBuilder();
def person1 = {
person(id: 1) {
firstName("John")
lastName("Doe")
data_labels {
mkp.yieldUnescaped(cData)
}
}
}
def personList = {
people {
out << person1
}
}
xml.bind(personList).toString()
}

def static main(def args) {
def example = new JTidyExample()
def singleLine = example.createMarkUp()
println "Before: \n ${singleLine}"
println "After: \n ${example.tidyMeUp(singleLine)}"
}

}



The following is output:


Before:

<people><person id='1'><firstName>John</firstName><lastName>Doe</lastName><data_labels><![CDATA[hello]]></data_labels></person></people>

Tidy (vers 26-Sep-2004) Parsing "InputStream"
no warnings or errors were found

After:

<people>
<person id='1'>
<firstName>John</firstName>
<lastName>Doe</lastName>
<data_labels>
<![CDATA[hello]]>
</data_labels>
</person>
</people>



Here we can see that our XML is now nicely indented. Want some more??? Check out Scott Davis' Groovy Recipes, it has a pretty sweet XML section!

UPDATE: Check out Paul Kings comments where he suggests using groovy.xml.XmlUtil.serialize(xml.bind(personList)). Sweet!