首页 > 解决方案 > 在 Groovy 中使用 XML 命名空间和 XmlSlurper - 如何正确查询路径?

问题描述

我有以下示例 xml:

<root>

<table xmlns:h="http://www.w3.org/TR/html4/">
  <tr>
    <td>Apples</td>
    <td>Bananas</td>
  </tr>
</table>

<table xmlns:f="https://www.w3schools.com/furniture">
  <name>African Coffee Table</name>
  <width>80</width>
  <length>120</length>
</table>

</root>
def slurper = new XmlSlurper().parseText(someXMLText)
def hNs = new groovy.xml.Namespace(
                    "http://www.w3.org/TR/html4/", 'h')
def fNs = new groovy.xml.Namespace(
                    "https://www.w3schools.com/furniture", 'h')
println slurper.root[hNs.table].tr.td //not giving any response

因为有两个具有不同标签的表格标签。如何Apples使用命名空间的 gpath 获取标签下的值。

标签: groovyxml-parsingxml-namespaces

解决方案


您对 XML 文档的使用不正确。当您定义一个类似 的命名空间时xmlns:h="http://www.w3.org/TR/html4/",您会创建一个必须显式使用的前缀。否则,如果文档未分配给任何节点,则无法使用此前缀查询文档。您需要将其分配给至少一个table标签才能使用它。

<h:table xmlns:h="http://www.w3.org/TR/html4/">
  <tr>
    <td>Apples</td>
    <td>Bananas</td>
  </tr>
</h:table>

但是,如果要为每个table节点(及其子节点)创建默认命名空间,则需要跳过前缀并定义一个没有它的命名空间。

<table xmlns="http://www.w3.org/TR/html4/">
  <tr>
    <td>Apples</td>
    <td>Bananas</td>
  </tr>
</table>

发现细微的差别——在第二个例子中,我们用xmlns属性定义了命名空间,而不是xmlns:h前一个例子中的那个。

使用默认命名空间时,可以使用该declareNamespace方法为默认命名空间定义前缀。这允许您使用像h:table这样的选择器来引用声明的命名空间映射中的前缀table定义的命名空间中的标记。h考虑以下示例:

def source = '''<root>

<table xmlns="http://www.w3.org/TR/html4/">
  <tr>
    <td>Apples</td>
    <td>Bananas</td>
  </tr>
</table>

<table xmlns="https://www.w3schools.com/furniture">
  <name>African Coffee Table</name>
  <width>80</width>
  <length>120</length>
</table>

</root>'''

def root = new XmlSlurper().parseText(source).declareNamespace([
    h: "http://www.w3.org/TR/html4/", 
    f: "https://www.w3schools.com/furniture"
])

assert root."h:table".tr.td.first().text() == "Apples"
assert root."h:table".tr.td.last().text() == "Bananas"
assert root."f:table".width.toInteger() == 80

table在此示例中,我们使用一个 XML 文档,该文档为标签定义了两个不同的默认命名空间。使用该declareNamespace方法,我们可以为这些命名空间定义前缀,以便我们可以在标签选择器中使用前缀。

如果出于某种原因,您需要在table节点级别使用前缀定义命名空间,则至少需要在顶层使用此前缀。

def source = '''<root>

<h:table xmlns:h="http://www.w3.org/TR/html4/">
  <tr>
    <td>Apples</td>
    <td>Bananas</td>
  </tr>
</h:table>

<f:table xmlns:f="https://www.w3schools.com/furniture">
  <name>African Coffee Table</name>
  <width>80</width>
  <length>120</length>
</f:table>

</root>'''

def root = new XmlSlurper().parseText(source).declareNamespace([
    h: "http://www.w3.org/TR/html4/",
    f: "https://www.w3schools.com/furniture"
])

assert root."h:table".tr.td.first().text() == "Apples"
assert root."h:table".tr.td.last().text() == "Bananas"
assert root."f:table".width.toInteger() == 80

希望能帮助到你。


推荐阅读