xpath /descendant-or-self — поиск узла в определенном дереве

Я читаю о сокращении '//', которое, по-видимому, является сокращением для:

'/потомок-или-я'

понятно, чего ожидать, скажем, от простого примера такого выражения, например,

//мой узел

Он вернет список узлов всех экземпляров в документе, найденных в корне, элементов с именем «myNode».

Однако что означает более сложное выражение, например:

//узел//мойузел

?

Поскольку // (сокращение от '/descendant-or-self') дважды соответствует корневому узлу, значит ли это, что первая часть выражения '//aNode' является избыточной и только увеличивает время, необходимое для завершения выполнение выражения (после того, как все еще были найдены только все выражения во всем документе «myNode»)?

'//myNode' и '//aNode//myNode' приведут к одному и тому же результату?

Наконец, если бы я искал в документе экземпляр узла «myNode», который был косвенным потомком узла «interestingTree». Но мне не нужен экземпляр узла myNode, который является непрямым потомком узла nonInterestingTree, как мне это сделать?

например, поиск в документе:

<root>
    <anode>
        <interestingTree>
            <unknownTree>
                <myNode/><!-- I want to find this one, not the other, where I don't know the path indicated by 'unknownTree' -->
            </unknownTree>
        </interestingTree>
        <nonInterestingTree>
            <unknownTree>
                <myNode/>
            </unknownTree>
        </nonInterestingTree>
    </anode>
    <anode>
        <someOtherNode/>
    </anode>
</root>

Спасибо!


person svaens    schedule 21.09.2012    source источник


Ответы (2)


'//myNode' и '//aNode//myNode' приведут к одному и тому же результату?

Да, в данном случае, потому что все myNodes также являются потомками anode. Однако в общем смысле //aNode//myNode, очевидно, не будет соответствовать узлам, у которых нет родителя anode в их дереве предков.

Экспат:

//aNode//myNode

будет игнорировать любую промежуточную иерархию между aNode и myNode, т. е. будет соответствовать /aNode/myNode, /anyNodes/anode/myNode и /anyNodes/anode/xyzNode/myNode

Что отвечает на ваш последний вопрос, вы можете найти узлы в интересном подпути следующим образом: (и снова игнорируя любые промежуточные элементы в иерархии)

//anode//interestingTree//myNode

в идеале, конечно, вы должны быть как можно более явными с вашим путем, так как // может привести к снижению производительности из-за потенциально большого количества элементов, которые необходимо найти.

Изменить Возможно, это поможет?

Я скорректировал ваш ввод xml для ясности:

<root>
    <anode>
        <interestingTree>
            <unknownTree>
                <myNode>
                    MyNode In Interesting Tree
                </myNode>
            </unknownTree>
        </interestingTree>
        <nonInterestingTree>
            <unknownTree>
                <myNode>
                    MyNode In Non-Interesting Tree
                </myNode>
            </unknownTree>
        </nonInterestingTree>
    </anode>
    <anode>
        <someOtherNode/>
    </anode>
    <bnode>
        <myNode>
            MyNode in BNode
        </myNode>
    </bnode>
</root>

При анализе таблицы стилей:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
    <xsl:template match="/">
        Matched by `//myNode`
        <xsl:apply-templates select="//myNode">
        </xsl:apply-templates>

        Matched by `//aNode//myNode`
        <xsl:apply-templates select="//anode//myNode">
        </xsl:apply-templates>

        Matched by `//aNode//interestingTree//myNode`
        <xsl:apply-templates select="//anode//interestingTree//myNode">
        </xsl:apply-templates>
    </xsl:template>

    <xsl:template match="myNode">
        <xsl:value-of select="text()"/>
    </xsl:template>
</xsl:stylesheet>

Возвращает следующее:

Matched by `//myNode`
        MyNode In Interesting Tree
        MyNode In Non-Interesting Tree
    MyNode in BNode

Matched by `//aNode//myNode`
        MyNode In Interesting Tree
        MyNode In Non-Interesting Tree

Matched by `//aNode//interestingTree//myNode`
        MyNode In Interesting Tree
person StuartLC    schedule 21.09.2012
comment
Итак, хотя в ходе тестирования я обнаружил //aNode == /descendant-or-self::aNode (и, что важно, НЕ потомок-или-само::aNode) , тем не менее мы можем быть уверены, что второй компонент xpath выражение //aNode//myNode будет только потомком 'aNode'? - person svaens; 21.09.2012
comment
@svaens Обновлено - надеюсь, прояснится? - person StuartLC; 21.09.2012
comment
да спасибо! Понятно. Хотя синтаксис удивителен, учитывая, что «//» означает «/потомок-или-я», а не просто «потомок-или-я». - person svaens; 21.09.2012
comment
// — это не что иное, как текстовое сокращение для /descendant-or-self::node()/ (включая косую черту в начале и конце), поэтому //aNode//myNode означает /descendant-or-self::node()/aNode/descendant-or-self::node()/myNode. Если // встречается в начале пути, он будет привязан к корню, если он встречается где-либо еще, он будет привязан к текущему месту (в частности, .//myNode относится к myNode потомку текущего узла, а не к корню). - person Ian Roberts; 21.09.2012
comment
@svaens Если вы просто «расширите» его, например. //aNode//myNode в /descendant-or-self::node()/anode/descendant-or-self::node()/myNode, становится более ясно, что // будет «начинаться» с корневого узла только в том случае, если перед //? нет узла. - person StuartLC; 21.09.2012
comment
@ Ян Робертс, спасибо! Теперь я действительно получил это! Может кто посоветует ХОРОШУЮ книгу? У меня где-то есть книга (я забыла, какая... для XSLT, я думаю, в ней есть раздел XPath), но она не очень тщательная. И я не нашел веб-сайт, который объяснил бы это так ясно, как это. - person svaens; 21.09.2012

Вы спрашиваете: «Приведут ли '//myNode' и '//aNode//myNode' к одному и тому же результату?»

Не обязательно. Первый вернет все элементы с именем myNode в документе; второй вернет все элементы с именем myNode, которые являются потомками элементов с именем aNode. В вашем примере XML эти два описания определяют один и тот же набор, но в некоторых документах XML это не так.

С другой стороны, выражения //aNode//myNode и //myNode[ancestor::aNode] всегда будут возвращать один и тот же набор узлов.

person C. M. Sperberg-McQueen    schedule 21.09.2012
comment
Привет, спасибо за ваш ответ. Да, я понял после того, как написал, что мой пример не самый лучший. На самом деле, я сначала задал свой вопрос «в целом», а затем только часть моего вопроса касалась примера XML-документа (но, к сожалению, я не сделал это настолько ясным, насколько это могло бы быть). - person svaens; 24.09.2012