2

我无法让following-sibling轴工作。

我有一个如下的 XML 文档。我尝试了类似的东西name(/T/p/q/following-sibling::*[1]。我知道name只会产生集合中的第一个,但是,该表达式不会返回任何内容。我正在xmlstarletUbuntu 上使用命令尝试 XPath。

<T>
<p><q>
<a1>A</a1>
<a2>A</a2>
<a3>A</a3>
<a4>A</a4>
<a5><b1>A</b1></a5>
</q></p>
</T>

给定输入 as /T/p/q,我想要其所有子元素节点的名称,但仅限于该级别。也就是说,输出应该是

a1
a2
a3
a4
a5
4

2 回答 2

2

在 XPath 1.0 中,不可能/T/p/q/*通过评估单个XPath 表达式来获得所需的所有子元素名称。

因此,需要在第一步中选择所有元素:

/T/p/q/*

然后,对于生成的 XmlNodeList 中包含的每个元素,一个新的 XPath 表达式(根据该元素求值)生成它的名称。

该算法的不同实现是可能的,对 XPath 1.0 使用不同的宿主语言。

下面是一个示例,其中 XPath 1.0 的宿主语言是 XSLT 1.0

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="/">
  <xsl:variable name="vWanted" select="/T/p/q/*"/>

  <xsl:for-each select="$vWanted">
   <xsl:value-of select="name()"/> <xsl:text> </xsl:text>
  </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

当此转换应用于提供的 XML 文档时:

<T>
    <p><q>
    <a1>A</a1>
    <a2>A</a2>
    <a3>A</a3>
    <a4>A</a4>
    <a5><b1>A</b1></a5>
    </q></p>
</T>

执行算法的两个步骤并产生想要的结果:

a1 a2 a3 a4 a5 

二、单个 XPath 2.0 表达式 - 解决方案:

/T/p/q/*/name()

对上述 XPath 2.0 表达式的求值产生一个由五个项目组成的序列,每个项目都是不同/T/p/q/*元素的名称。

于 2012-06-25T13:13:25.647 回答
1

实际上,它比你想象的要简单得多。

/T/p/q/*

返回 的节点集a1, a2, a3, a4, a5

它选择所有的孩子,q其中的孩子p是 的孩子 的孩子 的T孩子context node

我说的“孩子”是指“直系孩子”。不是“后裔”。因此,它只会选择a1-a5关卡上的节点。

正如您所说,该name()函数仅返回节点集中第一个节点的名称。我猜您必须遍历节点集才能将所有名称作为单个字符串获取。


使用xmlstarlet,您可以这样做:

xml sel -t -m "/T/p/q/*" -v "name(.)" -n input.xml

它匹配节点集,调用其中name(.)的每个节点,然后打印一个换行符。

  • -m匹配 XPath 表达式
  • -v打印 XPath 表达式返回的值
  • -n换行
  • 更多在这里

要使用following-sibling轴,您必须处于同一级别,例如要选择 的所有以下兄弟姐妹a2,您将使用/T/p/q/a2/following-sibling::*. 这将返回a3, a4, a5

于 2012-06-25T12:34:08.073 回答