В XSLT я могу запустить шаблон только один раз - PullRequest
6 голосов
/ 28 августа 2009

У меня есть блок XSLT, который может быть применен несколько раз в течение преобразования. Но я хочу, чтобы он действительно запускался только при первом применении, он должен быть пропущен все последующие времена. Как мне это сделать?

В качестве примера, вот что я хочу сделать: В таблице стилей я определяю глобальную переменную:

<xsl:variable name="run_once" select="0"/>

Тогда у меня есть шаблон, который вызывается несколько раз:

<xsl:template name="some_template">
    <xsl:if test="$run_once != 1">
        <xsl:variable name="run_once" select="1"/>
        <xsl:text>THIS TEXT SHOULD APPEAR ONLY ONCE</xsl:text>
    </xsl:if>
</xsl:template>

Конечно, это не работает, потому что переменные не могут быть изменены, только перегружены. Таким образом, после выхода some_template $ run_once снова становится равным 0, и текст применяется каждый раз, когда вызывается шаблон. Могу ли я установить какой-либо тип функциональности ifdef или другой глобальный объект?

Если вас интересует, почему я хочу это сделать, ниже приведено более подробное объяснение моей проблемы и решения, которое я использовал:

  • Мои данные - это данные в формате XML, вывод представляет собой отчет в формате WordML.
  • На входе у меня есть ряд узлов (названный theNode ). Некоторые, но не все эти узлы должны быть отображается на выходе. Узел должен отображаться только если XPATH hairyLogic верно (hairyLogic явно длинный и комплекс).
  • Узел также имеет тип (хранится в подузел). На входе все Узлы того же типа будут всегда быть сгруппированы вместе. в вывод, все узлы одного и того же тип должен быть сгруппирован под конкретный заголовок для этого типа (там должен быть только один заголовок для каждого типа).

Это решение, которое я использовал в итоге:

...
<xsl:apply-templates select="theNode[hairyLogic]"/>
...

<xsl:template match="theNode">
    <xsl:if test="count(preceding-sibling::theNode[type = current()/type and hairyLogic])=0">
        <xsl:choose>
            <xsl:when test="type = 'TYPE1a' or type = 'TYPE1b'">
                <xsl:call-template name="TYPE1Heading"/>
            </xsl:when>
            <xsl:when test="type = 'TYPE2'">
                <xsl:call-template name="TYPE2Heading"/>
            </xsl:when>
        </xsl:choose>
    </xsl:if>
    ...
</xsl:template>

Я решил использовать именованные шаблоны для заголовков, поскольку они содержат базовый WordML, который не зависит от каких-либо данных во входном XML.

Мне не нравится это решение, потому что hairyLogic повторяется, а оператор if сложен и труден для чтения. Может быть, у вас есть лучшее решение, которое не требует изменяемых переменных?

Ответы [ 2 ]

2 голосов
/ 01 сентября 2009

Я бы посоветовал использовать шаблоны совпадений над именованными шаблонами, потому что это больше, ну, каков XSLT-эквивалент pythonic ? XSLT-у? Я думаю, вы обнаружите, что с помощью этой методологии обработки вы сможете легче решать проблемы.

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

Можете ли вы уточнить, почему вы не можете определить, когда необходим первый экземпляр? Мы, вероятно, можем помочь создать выражение xpath, которое позволит вам делать то, что вы хотите. Э.Г.

<xsl:template name="some_template">
    <xsl:variable name="EXPRESSION" select=".[somelogic='true']"/>
    <xsl:if test="$EXPRESSION">
        <xsl:text>THIS TEXT SHOULD APPEAR ONLY ONCE</xsl:text>
    </xsl:if>
</xsl:template>

Поскольку XSLT является детерминированным - эффект полной функциональности, как выразился Грег, - (если вы не делаете странные дополнения), вы можете решить, когда первый раз подходит, применяя логику к входным данным. Кроме того, у вас есть доступ к узлу контекста в шаблоне, чтобы вы знали, откуда он вызывается.

2 голосов
/ 28 августа 2009

Поскольку XSLT является чисто функциональным языком, вы можете установить нет глобальных переменных.

Вместо этого вам придется выбрать обстоятельства, при которых вы называете свой шаблон some_template. Если вы хотите позвонить только один раз, сделайте только один звонок.

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