我正在尝试使用XmlSlurper
解析一些Android XML。对于给定的子节点,我想检测是否已指定具有特定命名空间的属性。
例如,在以下XML中,我想知道EditText
节点是否具有声明的'b'命名空间中的任何属性:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:b="http://x.y.z.com">
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
b:enabled="true" />
</LinearLayout>
我先致电:
def rootNode = new XmlSlurper().parseText(text)
获取根GPathResult
的句柄。当我遍历孩子时,我会得到一个groovy.util.slurpersupport.NodeChild
的实例。在这个课程中,我可以通过调用attributes()
来检查属性,如果是EditText
,则会返回以下地图:[layout_width: "fill_parent", layout_height: "wrap_content", enabled: "true"]
。
这一切都很好。但是,似乎没有办法查询给定属性的命名空间。我在这里错过了什么吗?
答案 0 :(得分:4)
您可以使用XmlParser
而不是XmlSlurper
并执行此操作:
def xml = '''<LinearLayout
| xmlns:android="http://schemas.android.com/apk/res/android"
| xmlns:b="http://x.y.z.com">
|
| <EditText
| android:layout_width="fill_parent"
| android:layout_height="wrap_content"
| b:enabled="true" />
|</LinearLayout>'''.stripMargin()
def root = new XmlParser().parseText( xml )
root.EditText*.attributes()*.each { k, v ->
println "$k.localPart $k.prefix($k.namespaceURI) = $v"
}
打印出来
layout_width android(http://schemas.android.com/apk/res/android) = fill_parent
layout_height android(http://schemas.android.com/apk/res/android) = wrap_content
enabled b(http://x.y.z.com) = true
要使用XmlSlurper,首先需要使用反射从根节点访问namespaceTagHints
属性:
def rootNode = new XmlSlurper().parseText(xml)
def xmlClass = rootNode.getClass()
def gpathClass = xmlClass.getSuperclass()
def namespaceTagHintsField = gpathClass.getDeclaredField("namespaceTagHints")
namespaceTagHintsField.setAccessible(true)
def namespaceDeclarations = namespaceTagHintsField.get(rootNode)
namespaceTagHints
是GPathResult的属性,是NodeChild
的超类。
然后,您可以交叉引用此映射以访问命名空间前缀,并打印出与上面相同的结果:
rootNode.EditText.nodeIterator().each { groovy.util.slurpersupport.Node n ->
n.@attributeNamespaces.each { name, ns ->
def prefix = namespaceDeclarations.find {key, value -> value == ns}.key
println "$name $prefix($ns) = ${n.attributes()"$name"}"
}
}
答案 1 :(得分:0)
到目前为止,我找到的唯一解决办法就是反思。
正如Damo在上面指出的那样,NodeChild
包含Node
属性,Node
内部是我需要获得的attributeNamespaces
地图。
Node
类不公开此属性(与attributes()
一样),并且它似乎只在build()
方法中使用。织补。
检索完节点后,我打电话给:
def attributeNamespacesField = node.getClass().getDeclaredField("attributeNamespaces")
attributeNamespacesField.setAccessible(true)
def attributeNamespacesMap = attributeNamespacesField.get(node)
它有效,但感觉不是 Groovy 。