The previous Reading XML using XmlSlurper, Reading XML using XmlParser, and Searching in XML with GPath recipes have been useful to learn the ingredients and the techniques for consuming and querying XML documents. In this recipe, we will cover how to produce XML using Groovy's MarkupBuilder
.
Let's create a bibliography XML similar to the one we used in the Reading XML using XmlSlurper recipe.
MarkupBuilder
, you first need to import it since it's not available by default:import groovy.xml.MarkupBuilder
java.io.StringWriter: def writer = new StringWriter()
MarkupBuilder
and pass the writer object to it:def xml = new MarkupBuilder(writer)
xml.bibliography { author('William Shakespeare') play { year('1595') title('A Midsummer-Night's Dream.') } }
println writer
We'll get the following output:
<bibliography> <author>William Shakespeare</author> <play> <year>1595</year> <title>A Midsummer-Night's Dream.</title> </play> </bibliography>
The previous XML construction code is a set of nested dynamic method calls that are mapped directly to XML element names. String parameter passed to those methods defines the content of the element (for example, author('William Shakespeare')
).
All the magic happens behind the scenes with the help of Groovy's Meta Object Protocol (MOP), which is heavily used by MarkupBuilder
(and in general, any other builder class within Groovy, see the Defining data structures as code in Groovy recipe in Chapter 3, Using Groovy Language Features). Every object in Groovy extends from groovy.lang.GroovyObject
, which offers two methods: invokeMethod
and getProperty
. Those methods are overridden by MarkupBuilder
to handle dynamic method names that are translated into an XML tree.
It is possible to construct any kind of markup with this approach including HTML/XHTML.
Another way to create XML content is by using the groovy.xml.StreamingMarkupBuilder
class. Its API is similar, but a bit more complex than the MarkupBuilder
API. On the other hand, it offers better memory management and allows creating large XML files with minimal memory footprint:
import groovy.xml.StreamingMarkupBuilder def builder = new StreamingMarkupBuilder() def bibliography = builder.bind { bibliography { author('William Shakespeare') play { year('1595') title('A Midsummer-Night's Dream.') } } } println bibliography
The previous code snippet achieves a similar result to the initial example.
In general, MarkupBuilder
to StreamingMarkupBuilder
is the same as XmlParser
(see the Reading XML using XmlParser recipe) is to XmlSlurper
(see the Reading XML using XmlSlurper recipe). There are three main differences between MarkupBuilder
and StreamingMarkupBuilder
:
StreamingMarkupBuilder
doesn't output the XML until a writer is explicitly passed, while MarkupBuilder,
by default, outputs to System.out
.MarkupBuilder
processes the XML generation synchronously while StreamingMarkupBuilder
generates the XML only when is passed to a Writer. It is possible, for instance, to define a number of closures containing snippets of XML and generate the markup only when needed.MarkupBuilder
formats the output for increased readability whereas StreamingMarkupBuilder
does not.3.21.100.62