Вопрос по XPath с функциями в нем - PullRequest
3 голосов
/ 03 декабря 2010

это дополнительный вопрос моей предыдущей темы:

Пожалуйста, помогите мне разобраться в этом XPath

У меня XPath как:

<xsl:value-of select="position()+count(preceding-sibling::*)-18"/>

В настоящее время я могу понять только его части, например, положение (). Кроме того, я знаю, что предыдущий брат должен выбрать всех братьев и сестер перед текущим узлом, но я понятия не имею, что означает это утверждение, когда они объединяются, как описано выше.

Может ли кто-нибудь помочь с пониманием этого XPath? заранее спасибо.

Ответы [ 6 ]

5 голосов
/ 03 декабря 2010

Ваше выражение выполняет некоторые вычисления, используя статическую позицию (из входного источника) и динамическую позицию (из текущего списка узлов).

Давайте посмотрим несколько примеров. Предположим, эта таблица стилей и этот вход:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="list">
        <xsl:copy>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="*">
        <xsl:copy>
            <xsl:value-of select="concat(position(),' + ',
                                         count(preceding-sibling::*),' = ',
                                         position() +
                                         count(preceding-sibling::*))"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

<list>
    <a/>
    <b/>
    <a/>
    <b/>
</list>

Выход:

<list>
    <a>1 + 0 = 1</a>
    <b>2 + 1 = 3</b>
    <a>3 + 2 = 5</a>
    <b>4 + 3 = 7</b>
</list>

Теперь изменив второе правило на match="a":

<list>
    <a>1 + 0 = 1</a>
    <a>3 + 2 = 5</a>
</list>

Итак, шаблоны не изменяют текущий список узлов

Что, если position() в шаблоне? Давайте изменим правило на match="a[position()=2]":

<list>
    <a>3 + 2 = 5</a>
</list>

Странно? Нет. В шаблоне XPath position() работает против своего собственного списка узлов контекста и направления оси. В этом случае: child::a[position()=2] означает второго a ребенка.

Это показывает, что position() в шаблонах работает с контекстом, отличным от position() в шаблоне содержимого.

Итак, как изменить текущий список узлов контекста? Ну, apply-templates и for-each инструкции.

Добавьте сейчас к инструкции apply-templates некоторый атрибут select, например select="a":

<list>
    <a>2 + 2 = 4</a>
</list>
2 голосов
/ 03 декабря 2010

Все ответы, кроме @Alejandro, имеют одинаковую общую ошибку :

Это не правда, что :

preceding-sibling::*

выбирает все узлы предшествующего брата.

Он выбирает только все элементы предшествующего брата.

Чтобы выбрать все узлы предшествующего брата, используйте :

preceding-sibling::node()

В XPath есть такие узлы :

  1. Корневой узел (обозначается /), также обозначается как document-node() в XPath 2.0

  2. Узлы элементов . такие как <a/>

  3. Текстовые узлы . В <a> Hello </a> текстовый узел является единственным потомком a и имеет строковое значение «Hello»

  4. Узлы комментариев . <!-- This is a comment-->

  5. Обработка инструкций узлов . <?someName I am a PI ?>

  6. Узлы атрибутов . В <a x="1"/> x это единственный атрибут a.

  7. Узлы пространства имен . <a xmlns:my="my:namespace"/> a имеет узел пространства имен со значением "my: namespace" и именем (префикс) my

Узлы первых 5 видов можно выбрать с помощью оси preceding-sibling:: :

preceding-sibling::node()

выбирает все родственные узлы от 1 до 5.

preceding-sibling::*

выбирает все элементы, предшествующие родным братьям

preceding-sibling::someName

выбирает все элементы с именем "someName", предшествующие родным братьям

preceding-sibling::text()

выделяет все текстовые узлы, предшествующие братьям и сестрам (полезно в смешанном контенте)

preceding-sibling::comment()

выбирает все узлы комментариев, предшествующие родным братьям.

preceding-sibling::processing-instruction()

выбирает всех предшествующих братьев и сестер, которые являются PI

preceding-sibling::processing-instruction('someName')

выбирает всех предшествующих братьев и сестер, которые являются PI и называются "someName".

2 голосов
/ 03 декабря 2010

position() возвращает позицию текущего узла в наборе узлов, который повторяется прямо сейчас.Предположим, есть четыре <foo> элемента:

<xml>
  <foo /><foo /><foo /><foo />
</xml>

, и вы повторяете их с помощью <xsl:apply-templates>:

<xsl:template match="/xml">
  <!-- this selects four nodes -->
  <xsl:apply-templates select="foo" />
</xsl:template>

<!-- this runs four times -->
<xsl:template match="foo">
  <xsl:value-of select="position()" />
</xsl:template>

Тогда это выдаст "1234".

count() считает узлы в наборе узлов.

preceding-sibling::* выбирает все элементы на оси preceding-sibling, как видно из текущего узла (если текущий узел не является атрибутом, так какатрибуты технически не имеют предшествующих братьев и сестер) .

<xsl:value-of select="position()+count(preceding-sibling::*)-18"/>

Теперь все должно быть понятно.Концепция XSLT, которую вы, вероятно, упускаете, - это концепция «текущего узла».Текущий узел - это контекст выполнения вашей программы XSLT.Всегда есть узел, который является текущим узлом, и большинство операций XSLT / XPath неявно работают с текущим узлом.

1 голос
/ 03 декабря 2010

preceding-sibling:: - это ось, которая возвращает набор узлов.В этом случае * рассказывает все предшествующие братья и сестры.count() подсчитывает количество узлов в наборе узлов.Таким образом, эта часть выражения дает нам общее количество узлов, у которых есть тот же родительский элемент, что и у текущего узла, которые появляются перед ним в документе.

0 голосов
/ 03 декабря 2010

Ваш код приведет к числу, которое будет равно:

Позиция в списке узлов Current , минус число любых предшествующих братьев и сестер, минус 18.

Вообще говоря, различные операторы могут быть объединены в выражения, как показано в примере.

Примечание: используйте position() с осторожностью, потому что иногда текущий список узлов не так легко увидеть.

0 голосов
/ 03 декабря 2010

position() будет оцениваться как число, представляющее текущее положение узлов в 1 индексируемом массиве оцениваемых узлов.Назовите это n .

preceding-sibling::* оценит число узлов-братьев до текущего и подсчитает, как это звучит (и вполне вероятно, что здесь будет равно n -1).

-18 должен быть самоочевидным :), так что вам остается вычислить позицию + количество предшествующих братьев и сестер - 18. Это будет весьма специфично для бизнес-задачи в отношениипочему вы хотите этот расчет, но это то, что у вас есть.

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