I am converting a Map to XML using the Groovy MarkupBuilder. This Map can contain simple key/value pairs, other Maps, or Lists of Maps. I am piggybacking from the code here.
import groovy.xml.MarkupBuilder
def map = [
key1:'value1',
key2:'value2',
nestedMap : [
key1:'bar1',
key2:'bar2'
],
select : [
[option:'foo1'],
[option:'foo2']
]
]
Closure renderMap( Map map ){
return {
for ( entry in map ){
switch( entry.value.getClass() ){
case Map :
"${entry.key}" renderMap( entry.value )
break
case List:
entry.value.collect { listEntry ->
"${entry.key}" renderMap( listEntry )
}
break
default :
"${entry.key}"( "${entry.value}" )
break
}
}
}
}
StringWriter writer = new StringWriter()
new MarkupBuilder(writer).root renderMap(map)
println writer.toString()
This part I’m concerned about prints out:
<select>
<option>foo1</option>
</select>
<select>
<option>foo2</option>
</select>
However, I am wondering if there is a way to get the select to encapsulate both of the options, like so:
<select>
<option>foo1</option>
<option>foo2</option>
</select>
I’ve tried playing around with the placement of the key, but to no avail. Am I going about this all wrong, or should I not be using the builder?
I think this will do what you want. The first two overloads take a map or a collection, and return a composed closure that can be passed to the builder method of the enclosing element to add the contents of the map or collection to the builder.
The third is a fallback, and just returns its arguments so they can be passed to the builder method. This handles the strings, but you could also pass it a closure if you want. I replaced the second
optionelement in the map you provided as an example of that.ComposedClosurewas added in Groovy 1.8, so this won’t work in earlier versions.