найти общего родителя с помощью Xpath - PullRequest
5 голосов
/ 11 февраля 2009

Мне было интересно, есть ли какой-нибудь способ получить доступ к общему родительскому узлу с помощью Xpath.

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

У меня есть текстовые узлы sometext и sometext2. Есть ли способ, которым я могу получить доступ к основной (общий родитель) этих двух узлов? Я не знаю макет XML, содержащий эти узлы.

Ответы [ 2 ]

15 голосов
/ 12 февраля 2009

Используйте следующее выражение XPath 1.0 :

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

, где $ v1 и $ v2 содержат два текстовых узла (если вы используете XPath вне XSLT, вам придется заменить $ v1 и $ v2 в вышеприведенном выражении на выражения XPath, которые выбирают каждый из этих двух текстовых узлов).

Объяснение :

Вышеупомянутое выражение XPath 1.0 находит пересечение двух наборов узлов : набор узлов всех предков элементов в $ v1 и набор узлов всех предков элементов в $ v2. Это делается с помощью так называемого метода Кайса для пересечения (после Майкла Кея, который открыл это в 2000 году). Используя метод пересечения Кейса, пересечение двух наборов узлов, $ 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()]
1 голос
/ 23 апреля 2017

Это кажется сложным. Просто попробуйте:

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

чтобы получить то есть ближайшего общего предка

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...