Найти позицию элемента в его родительском элементе с помощью XSLT / XPath - PullRequest
13 голосов
/ 20 июля 2011

Помимо переписывания большого количества кода XSLT (что я не собираюсь делать), есть ли способ найти положение элемента в его родительском элементе, когда контекст произвольно установлен на что-то другое? Вот пример:

<!-- Here are my records-->
<xsl:for-each select="/path/to/record">
  <xsl:variable name="record" select="."/>

  <!-- At this point, I could use position() -->
  <!-- Set the context to the current record -->
  <xsl:for-each select="$record">

    <!-- At this point, position() is meaningless because it's always 1 -->
    <xsl:call-template name="SomeTemplate"/>
  </xsl:for-each>
</xsl:for-each>


<!-- This template expects the current context being set to a record -->
<xsl:template name="SomeTemplate">

  <!-- it does stuff with the record's fields -->
  <xsl:value-of select="SomeRecordField"/>

  <!-- How to access the record's position in /path/to or in any other path? -->
</xsl:template>

ПРИМЕЧАНИЕ: Это упрощенный пример. У меня есть несколько ограничений, мешающих мне реализовать очевидные решения, такие как передача новых параметров в SomeTemplate и т. Д. Я действительно могу изменять только внутренние компоненты SomeTemplate.

ПРИМЕЧАНИЕ: Я использую Xalan 2.7.1 с EXSLT . Так что эти трюки доступны

Есть идеи?

1 Ответ

28 голосов
/ 20 июля 2011

Вы можете использовать

<xsl:value-of select="count(preceding-sibling::record)" />

или даже, вообще,

<xsl:value-of select="count(preceding-sibling::*[name() = name(current())])" />

Конечно, этот подход не будет работать, если вы обрабатываете список неравномерных узлов, то есть:

<xsl:apply-templates select="here/foo|/somewhere/else/bar" />

Информация о местоположении теряется в таком случае, , если вы не сохраните ее в переменной и не передадите ее в вызываемый шаблон:

<xsl:variable name="pos" select="position()" />
<xsl:for-each select="$record">
  <xsl:call-template name="SomeTemplate">
    <xsl:with-param name="pos" select="$pos" />
  </xsl:call-template>
</xsl:for-each>

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


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

Если вы обрабатываете (т. Е. «Применяете шаблоны к» или «перебираете») узлы в пределах одного родителя, это может быть одним и тем же.Если нет, это не так.

Заключительный совет № 2: Этот

<xsl:for-each select="/path/to/record">
  <xsl:variable name="record" select="."/>
  <xsl:for-each select="$record">
    <xsl:call-template name="SomeTemplate"/>
  </xsl:for-each>
</xsl:for-each>

эквивалентен следующему:

<xsl:for-each select="/path/to/record">
  <xsl:call-template name="SomeTemplate"/>
</xsl:for-each>

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

...