XPath:所有兄弟节点的名称

时间:2012-06-25 11:46:23

标签: xpath siblings

我无法让following-sibling轴工作。

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

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

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

a1
a2
a3
a4
a5

2 个答案:

答案 0 :(得分:2)

在XPath 1.0中,通过评估单个 XPath表达式,无法获得所需的子元素名称/T/p/q/*

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

/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 

<强> II。单个XPath 2.0表达式 - 解决方案:

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

对上述XPath 2.0表达式的评估会生成一个包含五个项目的序列,每个项目都是不同/T/p/q/*元素的名称。

答案 1 :(得分: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换新行
  • more here

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