使用Xpath查找公共父级

时间:2009-02-11 19:10:43

标签: xml xslt xpath

我想知道是否有办法使用Xpath访问公共父节点。

<outer>
<main>
           <a><b> sometext </b></a>
           <c><d> sometext2 </d></c>
</main>
</outer>

我有文本节点sometext和sometext2。有没有办法可以访问这两个节点的主(共同父节点)?我不知道包含这些节点的xml的布局。

2 个答案:

答案 0 :(得分:15)

使用以下XPath 1.0表达式

$v1/ancestor::*
   [count(. | $v2/ancestor::*) 
   = 
    count($v2/ancestor::*)
   ]
    [1]

其中$ v1和$ v2包含两个文本节点(如果您不在XSLT中使用XPath,则必须使用XPath表达式替换上述表达式中的$ v1和$ v2选择这两个文本节点中的每一个。)

<强>解释

上面的XPath 1.0表达式找到两个节点集的交集:$ v1的所有元素祖先的节点集和$ v2的所有元素祖先的节点集。 这是通过所谓的Kaysian交叉方法(在2000年发现这一点的Michael Kay之后)完成的。使用Kaysian方法进行交集,两个节点集的交集,$ ns1和$ ns2由以下XPath表达式选择

  $ns1[count(. | $ns2) = count($ns2)]

然后,从祖先的交叉点我们必须选择最后一个元素。但是,因为我们使用的是反向轴(祖先),所需的节点位置必须表示为1

通过应用以下转换,可以快速验证上述XPath表达式是否真正选择了最低共同祖先

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 <xsl:output method="text"/>

  <xsl:variable name="v1" select="/*/*/a/b/text()"/>
  <xsl:variable name="v2" select="/*/*/c/d/text()"/>

  <xsl:variable name="vCommonAncestor" select=
   "$v1/ancestor::*
       [count(. | $v2/ancestor::*) 
       = 
        count($v2/ancestor::*)
       ]
        [1]"
   />

    <xsl:template match="/">
      <xsl:value-of select="name($vCommonAncestor)"/>
    </xsl:template>
</xsl:stylesheet>

应用于最初提供的XML文档(更正为格式良好的XML):

<outer>
    <main>
        <a>
            <b>sometext</b>
        </a>
        <c>
            <d>sometext2</d>
        </c>
    </main>
</outer>

想要的结果(两个文本节点的最低共同祖先元素的名称)生成

主要

选择两个节点的最低共同祖先的XPath 2.0表达式更简单,因为它使用标准XPath 2.0运算符“intersect”:

   ($v1/ancestor::* intersect $v2/ancestor::*) 
                                         [last()]

答案 1 :(得分:1)

这看起来很复杂。试试吧:

xquery version "3.0";

let $test :=
    <outer>
    <main>
               <a><b> sometext </b></a>
               <c><d> sometext2 </d></c>
    </main>
    </outer>

return ($test//*[.//b][.//d])[last()]

获得最完美的共同祖先