Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Groovy XmlSlurper: get value of attribute that has an associated namespace

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)

like image 960
stempler Avatar asked Mar 05 '15 14:03

stempler


3 Answers

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]
like image 71
jalopaba Avatar answered Nov 09 '22 06:11

jalopaba


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
like image 41
tim_yates Avatar answered Nov 09 '22 06:11

tim_yates


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!'
like image 21
stempler Avatar answered Nov 09 '22 06:11

stempler