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

送分小仙女□ 提交于 2020-01-14 09:04:31

问题


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].@a1.text() == 'uno!'

rootNode.one[0].@a1.text() 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)


回答1:


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]



回答2:


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



回答3:


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



回答4:


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 = parsedXml.@package.text()
def pkg_ver = parsedXml.@'android:versionName'


来源:https://stackoverflow.com/questions/28880931/groovy-xmlslurper-get-value-of-attribute-that-has-an-associated-namespace

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!