I'm probably missing something obvious, as I'm a noob with Groovy, but I've searched but haven't found quite what I'm looking for. I have a test class where I'm reading in some XML; I want to insert an element at the beginning of a series of elements. I have figured out how to replace the first element, and I've figured out how to append a node to the end of the list, but I can't seem to grok how to insert an element at the beginning of the list (or ideally, any arbitrary position).
For example:
@Test
void foo()
{
def xml = """<container>
<listofthings>
<thing id="100" name="foo"/>
</listofthings>
</container>"""
def root = new XmlSlurper().parseText(xml)
root.listofthings.thing[0].replaceNode ( { thing(id:101, name:'bar') })
root.listofthings.appendNode ( { thing(id:102, name:'baz') })
def outputBuilder = new groovy.xml.StreamingMarkupBuilder()
String result = outputBuilder.bind { mkp.yield root }
print result
}
which yields:
<container>
<listofthings>
<thing id='101' name='bar'/>
<thing id='102' name='baz'/>
</listofthings>
</container>
What I really want is to insert a node at the beginning of listofthings, i.e. something to replace the call to replaceNode that would instead insert the thing with id 101 before the thing with id 100. I would also be nice if say, I had a longer list, to insert a node after the n'th element.
(Incidentally, is there a way to get the output in a more readable format? The output from StreamingMarkupBuilder all ends up as a single line of text; I reformatted it for clarity above)
Edit: I'm using 1.7.5, that's bundled with Eclipse, if it matters.
Groovy's internal XmlParser and XmlSlurper provide access to XML documents in a Groovy-friendly way that supports GPath expressions for working on the document. XmlParser provides an in-memory representation for in-place manipulation of nodes, whereas XmlSlurper is able to work in a more streamlike fashion.
Represents an arbitrary tree node which can be used for structured metadata or any arbitrary XML-like tree. A node can have a name, a value and an optional Map of attributes.
GPathResult, which is a wrapper class for Node. GPathResult provides simplified definitions of methods such as: equals() and toString() by wrapping Node#text().
One way you can do this by extracting the thing
elements out of your original xml into a list, manipulating the list, then rebuilding the document with this new list:
// function to take a single line xml output, and make it pretty
String renderFormattedXml( String xml ){
def stringWriter = new StringWriter()
def node = new XmlParser().parseText( xml )
new XmlNodePrinter( new PrintWriter( stringWriter ) ).print( node )
stringWriter.toString()
}
def xml = """<container>
<listofthings>
<thing id="100" name="foo"/>
</listofthings>
</container>"""
def root = new XmlSlurper().parseText(xml)
def things = root.listofthings*.thing
// Insert one at pos 0
things.add( 0, { thing( id:98, name:'tim' ) } )
// And one at the end
things.add( { thing( id:999, name:'zebra' ) } )
// And one at position 1
things.add( 1, { thing( id:99, name:'groovy' ) } )
def outputBuilder = new groovy.xml.StreamingMarkupBuilder()
String result = outputBuilder.bind {
container {
listofthings {
mkp.yield things
}
}
}
println renderFormattedXml( result )
which prints
<container>
<listofthings>
<thing id="98" name="tim"/>
<thing id="99" name="groovy"/>
<thing id="100" name="foo"/>
<thing id="999" name="zebra"/>
</listofthings>
</container>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With