stempler
stempler

Reputation: 750

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)

Upvotes: 5

Views: 9986

Answers (4)

Tertium
Tertium

Reputation: 6308

There is a simpler way:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
     android:versionCode="500" android:versionName="5.0.0" package="com.my.package"
    android:installLocation="preferExternal" >
...
</manifest >

parsing attr with namespace and without:

def parsedXml = (new XmlSlurper()).parse(android.sourceSets.main.manifest.srcFile)
def pkg_name = [email protected]()
def pkg_ver = parsedXml.@'android:versionName'

Upvotes: 1

jalopaba
jalopaba

Reputation: 8119

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]

Upvotes: 5

tim_yates
tim_yates

Reputation: 171084

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

Upvotes: 4

stempler
stempler

Reputation: 750

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!'

Upvotes: 1

Related Questions