Используйте значение переменной в режиме шаблонов apply-templates
Я хочу применить шаблон с режимом, который зависит от значения переменной.
<xsl:variable name="mode" select="@attribute"/>
<xsl:apply-templates mode="{$mode}"/>
Я получаю ошибку, которую таблица стилей не может быть скомпилирована. Значение режима должно быть QName, но это "{$ mode}".
Есть ли возможность использовать режимы, зависящие от переменных?
Ответы
Ответ 1
Единственный вариант, который вы должны использовать в определенном режиме на основе выражения, - это использовать
<xsl:choose>
<xsl:when test="@attribute = 'foo'">
<xsl:apply-templates mode="bar"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates/>
</xsl:otherwise>
</xsl:choose>
или то же самое с xsl:if
. Значение атрибута mode
должно быть QName
в XSLT 1.0, соответственно, в XSLT 2.0 допускает QName
или специальные токены, такие как #current
или #default
'. Но вы не можете вычислить значение mode
во время выполнения.
Ответ 2
режим не является допустимым кандидатом для шаблонов значений атрибутов (AVT). Вы просто не можете этого сделать.
Из Спецификация XSLT 2.0:
[Определение: в атрибуте, который обозначается как значение атрибута шаблон, такой как атрибут элемента с литеральным результатом, выражение можно использовать, окружая выражение с кудрявым скобки ({})].
режим не обозначается как AVT в спецификации, поэтому вы не можете этого сделать.
Ответ 3
Я получаю ошибку, которую таблица стилей не может быть скомпилирована. Значение mode должен быть QName, но это "{$ mode}".
Есть ли возможность использовать режимы, зависящие от переменных?
Нет, это не поддерживается ни в одной версии XSLT - 1.0, 2.0 или 3.0.
Как вы пытаетесь эмулировать функции более высокого порядка (HOF), вы можете использовать базовый принцип FXSL, чтобы сделать это в XSLT 1.0.
FXSL 1.x - это библиотека шаблонов, написанная в чистом XSLT 1.0, которая поддерживает/эмулирует HOF.
Вот полное решение, основанное на этих принципах:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:f="http://fxsl.sf.net" exclude-result-prefixes="f">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<f:inc/>
<f:double/>
<xsl:variable name="vModeInc" select="document('')/*/f:inc[1]"/>
<xsl:variable name="vModeDouble" select="document('')/*/f:double[1]"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<nums>
<xsl:apply-templates select="$vModeInc">
<xsl:with-param name="pNodes" select="node()"/>
</xsl:apply-templates>
</nums>
==============
<nums>
<xsl:apply-templates select="$vModeDouble">
<xsl:with-param name="pNodes" select="node()"/>
</xsl:apply-templates>
</nums>
</xsl:template>
<xsl:template match="f:inc">
<xsl:param name="pNodes"/>
<xsl:apply-templates select="$pNodes" mode="incr"/>
</xsl:template>
<xsl:template match="f:double">
<xsl:param name="pNodes"/>
<xsl:apply-templates select="$pNodes" mode="double"/>
</xsl:template>
<xsl:template match="num" mode="incr">
<num><xsl:value-of select=".+1"/></num>
</xsl:template>
<xsl:template match="num" mode="double">
<num><xsl:value-of select=".*2"/></num>
</xsl:template>
</xsl:stylesheet>
Когда это преобразование применяется к следующему документу XML:
<nums>
<num>01</num>
<num>02</num>
<num>03</num>
<num>04</num>
<num>05</num>
<num>06</num>
<num>07</num>
<num>08</num>
<num>09</num>
<num>10</num>
</nums>
вызывается желаемый, правильный результат - элементы nums/num
, обработанные в одном (каждом) из двух доступных режимов, в зависимости от указанной переменной - $vModeInc
(1 добавлено к каждое значение) или $vModeDouble
(каждое значение умножается на два):
<nums>
<num>2</num>
<num>3</num>
<num>4</num>
<num>5</num>
<num>6</num>
<num>7</num>
<num>8</num>
<num>9</num>
<num>10</num>
<num>11</num>
</nums>
==============
<nums>
<num>2</num>
<num>4</num>
<num>6</num>
<num>8</num>
<num>10</num>
<num>12</num>
<num>14</num>
<num>16</num>
<num>18</num>
<num>20</num>
</nums>