Groovy XmlSlurper: Get the value of an 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 a 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 result in an empty string. If we use rootNode.one[0].'@ex:a1'.text() , we get the correct value, but it depends on the namespace prefix used in the document - and you cannot rely on it to be the same for other documents, which is important for the corresponding namespace.

So the question is: How can XmlSlurper be used to access the attribute value of an attribute that has an associated namespace without specifying a namespace prefix? (it would be nice if it needed a full namespace)

+5
source share
4 answers

I think access to an attribute with an associated namespace cannot be done without specifying such a namespace. Otherwise, for the map containing the attributes, only the β€œlocal part of the name” will be used, which will lead to situations such as this old error (groovy 1.7.5) .

Perhaps the best way to do this 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] 
+5
source

A cleaner way would 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 
+4
source

The only solution I found was to use the ability to access attributes through representing GPathResult as Node .

A working example is as follows:

 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!' 
+1
source

There is an easier 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 and without namespace:

 def parsedXml = (new XmlSlurper()).parse(android.sourceSets.main.manifest.srcFile) def pkg_name = parsedXml.@package.text () def pkg_ver = parsedXml.@ 'android:versionName' 
+1
source

Source: https://habr.com/ru/post/1214746/


All Articles