【问题标题】:XPath : Names of all sibling nodesXPath : 所有兄弟节点的名称
【发布时间】:2012-06-25 11:46:23
【问题描述】:

我无法让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

【问题讨论】:

    标签: xpath siblings


    【解决方案1】:

    在 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 
    

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

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

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

    【讨论】:

      【解决方案2】:

      其实它比你想象的要简单得多。

      /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

      【讨论】:

      • 谢谢,Slanec。如何使用 /T/p/q/* 只返回节点名称? name 函数只会返回第一个?至于您的following-sibling 示例,问题是,我不会事先知道q 的第一个(或任何)孩子的名字。抱歉,我之前没有澄清。
      • @cogitoergosum 我用完整的xmlstarlet 查询更新了答案,以获取所有名称。
      • 谢谢你,斯莱尼克!它有帮助。 @Dimitre Novatchev,我会使用您的解决方案。但是,我的要求是在 SQL 中为 Derby 数据库包装 XPath(我刚才做了)。无论如何,谢谢!
      • @cogitoergosum 然而 - 接受到 Dimitre :)。无论如何,我很高兴能帮上忙,我以前在 xmlstarlet 上遇到了一些麻烦......
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-06
      相关资源
      最近更新 更多