xml.MarkupBuilder in Groovy

groovy, programming

Typical use of the builder starts with:

import groovy.xml.MarkupBuilder

def writer = new StringWriter()
def xml = new MarkupBuilder(writer)

...

String generatedXml = writer.toString()

Then the “building” part is what’s not documented all that well.

Fundamentals

To get element and value:

xml.Outer("hello") 

Output:

<Outer>hello</Outer>

To add attributes, pass them as a map to the function:

xml.Outer(xmlns:'http://www.abc.com/blahblahblah')

Output:

<Outer xmlns:"http://www.abc.com/blahblahblah" />

To add children, add a closure in which to add more tags:

xml.Outer(xmlns:'http://www.abc.com/blahblahblah') {
   Inner("inner val")
}

Output:

<Outer xmlns:"http://www.abc.com/blahblahblah">
   <Inner>inner val</Inner>
</Outer>

Adding some attributes AND value to Inner:

xml.Outer(xmlns:'http://www.abc.com/blahblahblah') {
   Inner(id:"myId", "inner val")
}

Output:

<Outer xmlns:"http://www.abc.com/blahblahblah">
   <Inner id="myId">inner val</Inner>
</Outer>

NOTE how the Inner() call: it’s a Map followed by a String.

Loops

Turns out we can add code (such as loops) inside the closure:

xml.Outer(xmlns:'http://www.abc.com/blahblahblah') {
   Inner(id:"myId", "inner val")
   (1..5).each {i -> 
      MoreInner("innerChild ${i}")
   }
}

Output:

<Outer xmlns='http://www.abc.com/blahblahblah'>
  <Inner id='myId'>inner val</Inner>
  <MoreInner>innerChild 1</MoreInner>
  <MoreInner>innerChild 2</MoreInner>
  <MoreInner>innerChild 3</MoreInner>
  <MoreInner>innerChild 4</MoreInner>
  <MoreInner>innerChild 5</MoreInner>
</Outer>

Other than loops, more sophisticated code can be used. But that will complicate the code. Which brings us to functions.

Function calls

def addInnerChildren(builder) {
   builder.Inner(id:"myId", "inner val") {
      (1..5).each {i -> 
         MoreInner("innerChild ${i}")
      }
   }
}

xml.Outer(xmlns:'http://www.abc.com/blahblahblah') {
   addInnerChildren(xml)
}

Output:

<Outer xmlns='http://www.abc.com/blahblahblah'>
  <Inner id='myId'>inner val</Inner>
  <MoreInner>innerChild 1</MoreInner>
  <MoreInner>innerChild 2</MoreInner>
  <MoreInner>innerChild 3</MoreInner>
  <MoreInner>innerChild 4</MoreInner>
  <MoreInner>innerChild 5</MoreInner>
</Outer>

Prefix for namespace

It’s a bit cumbersome; we have to quote the “tag”:

xml.'hahaha:Outer'('xmlns:hahaha': 'http://www.abc.com/blahblahblah') {
   whatever('floats')
   'hahaha:your'('boat')
}

Output:

<hahaha:Outer xmlns:hahaha='http://www.abc.com/blahblahblah'>
  <whatever>floats</whatever>
  <hahaha:your>boat</hahaha:your>
</hahaha:Outer>

Dynamic tags

Finally, if we do not know the exact tag yet:

String tag = "hahaha"

...

xml."${tag}"(xmlns: 'http://www.abc.com/blahblahblah') {
   whatever('floats your boat')
}

Output:

<hahaha xmlns='http://www.abc.com/blahblahblah'>
  <whatever>floats your boat</whatever>
</hahaha>