Как посчитать обращения шаблона в XSLT? - PullRequest
5 голосов
/ 08 сентября 2010

У меня есть сценарий XSLT, который я хотел бы нумеровать последовательно при каждом вызове шаблона.Таким образом, очень сокращенная версия выглядит примерно так:

<xsl:call-template name="insertHeader" />
<xsl:for-each ...>  
    <xsl:call-template name="insertHeader" />
    ...
</xsl:for-each>
<xsl:call-template name="insertHeader" />

<xsl:template name="insertHeader>
    This is item number <xsl:value-of select="$numberOfInvocations />
</xsl:template>

Очевидно, что функция $ numberOfInvocations не работает, и в XSLT вы не можете увеличить глобальную переменную-счетчик, которая выглядит как очевиднаяподход на процедурном языке.Я хотел бы, чтобы он распечатывал 1 при первом вызове шаблона, 2 при втором и т. Д. Как мне поступить?Возможно ли это даже удаленно в XSLT?

Спасибо:)

Редактировать: Итак, было несколько комментариев, которые недостаточно четко определены.Что я хочу сделать, так это пометить серию таблиц в (HTML) выводе.Наиболее очевидный способ сделать это - вызвать функцию (вы, вероятно, можете сказать, что я здесь не мастер XSLT), которая будет автоматически увеличивать число каждый раз.Я думаю, причина, по которой это кажется настолько сложной, заключается в том, что именно XSLT определяет, где эти таблицы появляются, а не ввод.это никогда не сработает.В любом случае, спасибо:)

Ответы [ 5 ]

6 голосов
/ 08 сентября 2010

В функциональном языке как XSLT не определен «порядок вычислений» .

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

Например, , ничто не ограничивает <xsl:apply-templates> для применения шаблонов в том же порядке во времени, что и порядок документов узлов в выбранном списке узлов. Это может быть сделано параллельно, что означает в любом порядке .

Многие процессоры XSLT выполняют lazy evaluation, что означает, что определенная инструкция XSLT будет оцениваться только тогда, когда она действительно необходима, а не в соответствии с ее текстовым порядком в таблице стилей XSLT. Часто некоторые инструкции вообще не выполняются.

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

Запрошенная нумерация может быть может быть произведена с использованием рекурсии (как правило) и в стиле продолжения CPS или Monads (точнее).

Библиотека FXSL (обе версии 1 - для XSLT 1.0 и версии 2 - для XSLT 2.0) содержит шаблоны, которые можно использовать для организации такой нумерации: foldl, foldr, iter, iterUntil, scanl , сканер, ... и т. д.

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

4 голосов
/ 08 сентября 2010

Вы пробовали функцию position()?

Вот фрагмент из одного из моих проектов, может быть, это полезно:

<xsl:variable name="count" select="count(../ownedParameter[@name])" />
$<xsl:value-of select="@name" />=null
<xsl:if test="$count > 1 and position()!=last()">,</xsl:if>

Вы должны быть в состоянии сделать что-то вроде:

<xsl:template name="insertHeader>
    This is item number <xsl:value-of select="position()" />
</xsl:template>

... по крайней мере, я думаю, что это сработает. Если нет, вам может потребоваться выполнить вызов count() в блоке for-each.

2 голосов
/ 09 сентября 2010

numberOfInvocations должен быть вычислен вне шаблона и задан в качестве параметра.Внутри for-each вы можете получить номер итерации, используя position().

. В следующей таблице стилей я добавил параметр pos к insertHeader.

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:s="uri:sample">
  <xsl:output type="text"/>

  <s:sample>
    <table>Table A</table>
    <table>Table B</table>
  </s:sample>

  <xsl:template match="/">
    <xsl:apply-templates select="document('')//s:sample"/>
  </xsl:template>

  <xsl:template match="s:sample">
    <xsl:call-template name="insertHeader">
      <xsl:with-param name="pos" select="1"/>
    </xsl:call-template>

    <xsl:variable name="node-set" select="table"/>
    <xsl:variable name="node-set-count" select="count($node-set)"/>
    <xsl:for-each select="$node-set">
      <xsl:call-template name="insertHeader">
        <xsl:with-param name="pos" select="1+position()"/>
      </xsl:call-template>
      <xsl:value-of select="."/>
      <xsl:text>
</xsl:text>
    </xsl:for-each>

    <xsl:call-template name="insertHeader">
      <xsl:with-param name="pos" select="2+$node-set-count"/>
    </xsl:call-template>

  </xsl:template>

  <xsl:template name="insertHeader">
    <xsl:param name="pos"/>
    <xsl:text>This is item number </xsl:text><xsl:value-of select="$pos" />
    <xsl:text>
</xsl:text>
  </xsl:template>

</xsl:stylesheet>

Примечание: образец документа встроен в таблицу стилей, поэтому примените таблицу стилей к себе, чтобы просмотреть результат.

$ xsltproc 3663349.xslt 3663349.xslt
This is item number 1
This is item number 2
Table A
This is item number 3
Table B
This is item number 4
2 голосов
/ 08 сентября 2010

Вы можете сделать это в XSLT 1.0, используя рекурсивный шаблон.

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

Каковы ваши намерения с этим?Может быть, мы сможем предложить вам более XSLTish решение.Я верю, что вы могли бы решить вашу проблему (если я думаю, что это ...), используя xsl:number и используя правильный шаблон в атрибуте @count.

XSLT 1.0:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

  <xsl:template match="/">
    <xsl:call-template name="insertHeader"/>
  </xsl:template>

  <xsl:template name="insertHeader">
    <xsl:param name="num" select="1"/>
    <xsl:value-of select="concat('This is item number ', $num, '&#x0a;')"/>
    <xsl:if test="$num &lt; 10">
      <xsl:call-template name="insertHeader">
        <xsl:with-param name="num" select="$num + 1"/>
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>

Который выдаст:

This is item number 1
This is item number 2
This is item number 3
This is item number 4
This is item number 5
This is item number 6
This is item number 7
This is item number 8
This is item number 9
This is item number 10
0 голосов
/ 06 ноября 2013

<xsl:number /> просматривает древовидную структуру и нумерует ее сверху вниз

xslt: <h2><xsl:number />.<xsl:value-of select="/t/tittel" /></h2>

из xml:
<tittel>e</tittel>
<tittel>ex</tittel>
<tittel>exa</tittel>
<tittel>example</tittel>

превращается в:

<h2>1. e</h2>
<h2>2. ex</h2>
<h2>3. exa</h2>
<h2>4. example</h2>

больше информации: http://www.xml.com/pub/a/2002/12/11/autocount.html

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