I have an XML document that contains attributes with qualified names. I want to get the attribute value using XmlSlurper, but trying to access the attribute without specifying the namespace does not work (below is a minimal example).
def rootNode = new XmlSlurper().parseText(
'''<root xmlns:ex="http://example.com">
<one ex:a1="uno!"/>
<ex:two>Some text!</ex:two>
</root>''' )
assert rootNode.one[0][email protected]() == 'uno!'
rootNode.one[0][email protected]()
will yield an empty string. If using rootNode.one[0].'@ex:a1'.text()
we get the correct value, but this is dependent on the namespace prefix used in the document - and that can't be relied upon to be the same for other documents, the associated namespace is what matters.
So the question is: How can XmlSlurper be used to access an attribute value of an attribute that has an associated namespace without the need to specify the namespace prefix? (it would be OK if supplying the whole namespace is needed)
I think that accessing an attribute with an associated namespace can't be done without specifying such namespace. Otherwise, only the "local part of the name" would be used for the map holding the attributes, leading to situations like this old bug (groovy 1.7.5).
Maybe the best way to do that is to use groovy.xml.Namespace
and use it to access the attribute:
import groovy.xml.Namespace
def xml = '''
<root xmlns:ex="http://example.com">
<one ex:a1="uno!"/>
<ex:two>Some text!</ex:two>
</root>'''
def ns = new Namespace('http://example.com', 'ex')
def slurper = new XmlSlurper(false, true)
def slurped = slurper.parseText(xml)
assert 'uno!' == slurped.one[0].attributes()[ns.a1.toString()]
def parser = new XmlParser(false, true)
def parsed = parser.parseText(xml)
assert 'uno!' == parsed.one[0].attributes()[ns.a1]
A cleaner method might be to use find
and localPart
with XmlParser
:
def rootNode = new XmlParser().parseText(
'''<root xmlns:ex="http://example.com">
<one ex:a1="uno!"/>
<ex:two>Some text!</ex:two>
</root>''' )
rootNode.one[0].attributes().find { it.key.localPart == 'a1' }?.value
The only solution I found is making use of the possibility to access the attributes via the representation of a GPathResult as Node.
The working example looks like this:
def rootNode = new XmlSlurper().parseText(
'''<root xmlns:ex="http://example.com">
<one ex:a1="uno!"/>
<ex:two>Some text!</ex:two>
</root>''' )
// map of attributes, or null
def oneAttrs = rootNode.one[0].nodeIterator().next()?.attributes()
assert oneAttrs
// retrieve attribute by qualified name
assert oneAttrs['{http://example.com}a1'] == 'uno!'
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