【问题标题】:find common parent using Xpath使用 Xpath 找到共同的父级
【发布时间】:2018-09-21 00:00:00
【问题描述】:

我想知道是否有任何方法可以使用 Xpath 访问公共父节点。

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

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

【问题讨论】:

    标签: xml xslt xpath


    【解决方案1】:

    使用以下 XPath 1.0 表达式

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

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

    说明

    上面的 XPath 1.0 表达式找到两个节点集的交集:$v1 的所有元素祖先的节点集和 $v2 的所有元素祖先的节点集。 这是通过所谓的 Kaysian 交集方法完成的(在 Michael Kay 之后,他在 2000 年发现了这一点)。使用 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 运算符“相交”:

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

    【讨论】:

    • 嗨,作为您提到的 Xpath 表达式的后续行动。我对 XPath 有点陌生,并且正在使用 Node 对象(java)访问文本节点。如何使用我拥有的两个节点对象作为参数来编译这个表达式?类似 (n1/ancestor::* intersect n2/ancestor::*) .. ?谢谢
    • 将 $v1 替换为:/*/*/a/b/text(),将 $v2 替换为:/*/*/c/d/text()
    • Dimitre,我喜欢你们每个人都使用相同的方法回答!我真的很认真!我只是使用了一个修改版本:$v1/ancestor-or-self::*[count(. | $v2/ancestor-or-self::*) = count($v2/ancestor-or-self::*)][1],以防其中一个节点是另一个节点的父节点(或者它们都是相同的)。我只希望我能理解该方法足以记住它,而无需每次都查找它!
    • @CJDennis,这只是一个众所周知的集合论恒等式,其含义很简单:来自$ns1的所有节点也属于$ns2
    【解决方案2】:

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

    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()]
    

    得到最近的共同祖先

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-08
      • 1970-01-01
      • 2021-04-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多