I'm iterating through the child elements of a flattish XML, and adding a certain attribute for elements that are empty.
import groovy.xml.XmlUtil
import groovy.xml.MarkupBuilder
import groovy.xml.XmlSlurper
def xmlTxt = '''<root>
<node>
<element/>
<element/>
</node>
</root>'''
def xml = new XmlSlurper().parseText(xmlTxt)
xml.node.'*'.each {
if ( it == "") {
it.'@foo' = "bar"
}
}
return XmlUtil.serialize(xml)
The result for this is
<?xml version="1.0" encoding="UTF-8"?><root>
<node>
<element foo="bar"/>
<element foo="bar"/>
</node>
</root>
Now, my real requirement is to change the element so that <element xsi:nil="true"/>
, where xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
I've tried using .declareNamespace(xsi:'http://www.w3.org/2001/XMLSchema-instance')
when creating the XmlSlurper instance, and then it.'@xsi:nil' = 'true'
when adding the attribute, but this results in an error. Is there a quick way to accomplish this with the syntax I'm using?
Here is the best I could come up with:
import groovy.xml.XmlUtil
import groovy.xml.MarkupBuilder
import groovy.xml.XmlSlurper
def xmlTxt = '''
<root>
<node>
<element/>
<element/>
</node>
</root>'''
def parseSlurper( text ) {
def xml = new XmlSlurper().parseText(text)
xml.node.'*'.replaceNode {
element('xsi:nil': true, "xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance")
}
// this should work, but doesn't. But it doesn't throw an error either.
// xml.node.'*'.each {
// it.'@xsi:nil' = true
// it.'xmlns:xsi' = "http://www.w3.org/2001/XMLSchema-instance"
// }
return xml
}
def parseXmlParser( text ) {
def xml = new XmlParser().parseText(text)
xml.node.'*'.each {
it.replaceNode {
element('xsi:nil': true, "xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance")
}
}
return xml
}
def xml = parseSlurper( xmlTxt )
//def xml = parseXmlParser( xmlTxt )
println XmlUtil.serialize(xml)
The issue you were having was that it didn't know about the xsi
namespace because it wasn't in your root node definition. Using the declareNamespace
wasn't working either since it didn't see that definition. I suspect it was added after the parsing so it couldn't see it. There are some mentions of this in the docs.
I tried putting the namespace definition directly in the XML:
def xmlTxt = '''
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<node>
<element/>
<element/>
</node>
</root>'''
...but it still didn't seem to see it when I added the @xsi:nil
attribute to the element.
The only thing that worked was replacing the node with a newly defined node that included the xmlns:xsi
definition. Otherwise it was "unbounded" and an error was thrown.
I also checked XmlParser
in case it handled namespaces differently, but it was pretty much the same result as XmlSlurper
. I included the code should you want to experiment with it too.
That's about as close as I could get it.