Что exsl:node-set считает корневым узлом?

У меня возникли проблемы с пониманием того, как работает функция exsl:node-set.

У меня есть некоторый XML, который я расширяю и использую для динамического заполнения набора exsl:node. Допустим, в настоящее время он находится в таком формате:

<xsl:variable name="wrap">
    <nodes>
        <node/>
        <node/>
        <node/>
    </nodes>
</xsl:variable>
<xsl:variable name="wrapNodeSet" select="exsl:node-set($wrap)"/>

Это работает по мере необходимости, и вывод $wrapNodeSet показывает разметку узлов выше. Имя корневого узла отображается как «узлы» с использованием имени ($wrapNodeSet/*).

Теперь мне нужно расширить это, чтобы иметь 2 узла и динамически заполнять набор узлов. Так:

    <xsl:variable name="wrap">
    <nodes tier="a">
        <node/>
        <node/>
        <node/>
    </nodes>
    <nodes tier="b">
        <node/>
        <node/>
        <node/>
    </nodes>
</xsl:variable>
<xsl:variable name="wrapNodeSet" select="exsl:node-set($wrap)/nodes[@tier='b']"/>

Вывод набора узлов включает элемент узлов, но вывод имени корневого узла теперь изменяется на «узел».

Может кто-нибудь объяснить, почему элемент узлов все еще выводится?


person Alex B    schedule 02.07.2012    source источник


Ответы (3)


<xsl:variable name="wrapNodeSet" 
              select="exsl:node-set($wrap)/nodes[@tier='b']"/>

Это выбирает любой элемент nodes из дерева, полученного с расширением node-set(), который (элемент nodes) имеет атрибут tier со значением 'b'.

Затем:

name($wrapNodeSet/*)

производит имя первого дочернего элемента первого узла, содержащегося в $wrapNodeSet. Поскольку $wrapNodeSet содержит ровно один элемент nodes, а элемент nodes имеет только node дочерних элементов, первым таким дочерним элементом является элемент node и его имя, так как имя любого элемента node"node".

Почему вы видите что-то неожиданное в этом результате?

Другими словами:

Применение ext:node-set() к $wrap в обоих случаях создает одно и то же дерево, но во втором случае вы используете другое, более длинное выражение XPath для результата ext:node-set($wrap) — отсюда и разные результаты, которые вы получаете при оценке этих двух разных выражений XPath.

person Dimitre Novatchev    schedule 02.07.2012

exslt:node-set имеет очень неформальную спецификацию и, вероятно, есть детали того, какие реализации отличаются друг от друга. Это, безусловно, так в крайних случаях, например, если аргументом exstl:node-set является нечто иное, чем фрагмент результирующего дерева.

Поведение, которое я ожидал бы, состоит в том, что exslt:node-set() всегда предоставляет «корневой узел» (то, что XPath 2.0 называет «узел документа»). Корневой узел, определенный в XPath 1.0, не имеет имени. В вашем первом примере корневой узел имеет один дочерний элемент, имя которого «узлы». Во втором примере у корневого узла есть два дочерних элемента, оба из которых имеют имя «узлы».

Вы говорите, что «вывод имени корневого узла теперь меняется на« узел »», что сбивает с толку, потому что «корневой узел», как определяет термин XPath 1.0, никогда не имеет имени. Что вы на самом деле вывели?

person Michael Kay    schedule 02.07.2012

Если я правильно понял ваш вопрос, я считаю, что «интуитивно» то, что происходит (фактические закулисные детали реализации, вероятно, немного отличаются), в первую очередь, ваша переменная указывает на «анонимный набор узлов» переменная, которая оборачивает элемент <nodes>. Таким образом, name($wrapNodeSet/*) получает имена всех прямых дочерних элементов этого анонимного набора узлов, что в данном случае является просто именем одного элемента <nodes>.

Во втором случае вы зашли глубже, чем набор анонимных узлов, и переменная содержит непосредственно один элемент nodes[@tier='b']. В этом случае name($wrapNodeSet/*) вместо этого выбирает все прямые дочерние элементы этого элемента <nodes> и возвращает 3 экземпляра <node>. Если вы выберете значение select для этого, по умолчанию будет отображаться только первый, поэтому вы просто увидите «узел» на выходе.

Чтобы получить имя корня для второго экземпляра, просто выполните name($wrapNodeSet) напрямую, и вы должны увидеть «узлы». Выполнение $name(wrapNodeSet) в первом случае ничего не вернет, так как набор анонимных узлов не имеет имени.

person actionshrimp    schedule 02.07.2012