Применение различных шаблонов XSLT в зависимости от параметра
что у меня?
у меня есть ASP.NET проект, в котором у меня есть файл XSLT со многими определенными шаблонами. Только один шаблон будет использоваться одновременно в зависимости от выбора пользователя для отображения содержимого на веб-странице. Это выглядит примерно так:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="TemplateName"></xsl:param>
<xsl:template match="Title_Only">
...template Title_Only body...
</xsl:template>
<xsl:template match="Image_Only">
...template Image_Only body...
</xsl:template>
<xsl:template match="Title_And_Image">
...template Title_And_Image body...
</xsl:template>
</xsl:stylesheet>
чего я хочу?
Я хочу передать имя шаблона TemplateName
в качестве параметра и иметь возможность применять соответствующий шаблон к данным.
может кто-нибудь, пожалуйста, скажите мне, как я могу достичь этого?
3 ответов
вы не можете использовать значение параметра или переменной в шаблон в XSLT 1.0. Однако вы можете применять шаблоны условно из одного шаблона, например:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="TemplateName"/>
<xsl:template match="/">
<xsl:apply templates select="something[some_condition=$TemplateName]"/>
</xsl:template>
</xsl:stylesheet>
...а затем просто настройте шаблоны, чтобы соответствовать каждому типу узла индивидуально. Шаблоны будут применяться только к тем вещам, которые соответствуют вашему select
выражение, которое основано на параметре.
пример условного применения шаблоны
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable name="TemplateName" select="'Title_Only'" />
<xsl:template match="/">
<xsl:apply-templates select="test/val[@name=$TemplateName]" />
</xsl:template>
<xsl:template match="val">
<xsl:value-of select="@name" />
</xsl:template>
</xsl:stylesheet>
приложенный к этому входу:
<test>
<val name="Title_Only" />
<val name="Image_Only" />
<val name="Title_And_Image" />
</test>
выдает:
Title_Only
...на основе значения $TemplateName
. (Обратите внимание, что в этом примере используется переменная, но идея та же.)
отдельные шаблоны с помощью режима
Если вам действительно нужен совершенно другой шаблон в каждом случае, используйте режимы. Этим стилем:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable name="TemplateName" select="'Title_Only'" />
<xsl:template match="/">
<xsl:choose>
<xsl:when test="$TemplateName='Title_Only'">
<xsl:apply-templates select="test/val" mode="Title_Only" />
</xsl:when>
<xsl:when test="$TemplateName='Image_Only'">
<xsl:apply-templates select="test/val" mode="Image_Only" />
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="test/val" mode="Title_And_Image" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="val" mode="Title_Only">
<xsl:value-of select="@title" />
</xsl:template>
<xsl:template match="val" mode="Image_Only">
<xsl:value-of select="@img" />
</xsl:template>
<xsl:template match="val" mode="Title_And_Image">
<xsl:value-of select="@title" />/
<xsl:value-of select="@img" />
</xsl:template>
</xsl:stylesheet>
применить к этому источник:
<test>
<val title="some title" img="some image"/>
</test>
выдает:
some title
используется нужный шаблон, основанный на значении параметра.
Я хочу передать имя шаблона TemplateName как параметр и быть возможность применить соответствующий шаблон на данные.
как в XSLT 1.0, так и в XSLT 2.0 незаконно иметь такую конструкцию, как:
<xsl:call-template name="{$vTemplateName}"/>
в то время как XPath 3.0 (XSLT 3.0) вводит элементы функций и HOF (функции более высокого порядка), HOF можно эмулировать в предыдущих версиях XSLT. Для получения дополнительной информации прочитайте статьи на домашней странице FXSL.
вот упрощенный пример идеи, лежащей за FXSL:
<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>
учитывая этот пример XML, у нас есть два шаблона, один из которых производит сумму всех num
элементы и другие производят их конкатенацию. Мы хотим передать нужную операцию в качестве параметра.
вот как это сделать (обратите внимание, что ничто в исходном XML не говорит нам, какая операция использовать):
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="my:my">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:param name="pOp" select="'sum'"/>
<my:ops>
<op>sum</op>
<op>concat</op>
</my:ops>
<xsl:variable name="vOps" select=
"document('')/*/my:ops/*"/>
<xsl:template match="/">
<xsl:apply-templates select="$vOps[. = $pOp]">
<xsl:with-param name="arg1" select="/*/*"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="op[.='sum']">
<xsl:param name="arg1"/>
<xsl:value-of select="sum($arg1)"/>
</xsl:template>
<xsl:template match="op[.='concat']">
<xsl:param name="arg1"/>
<xsl:for-each select="$arg1">
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
при применении на XML-документе выше, желаемый, правильный результат получается:
55
когда мы заменяем:
<xsl:param name="pOp" select="'sum'"/>
С:
<xsl:param name="pOp" select="'concat'"/>
и примените новое преобразование, снова будет получен желаемый, правильный результат:
01020304050607080910
обратите внимание:
основной (используя) шаблон может и обычно будет находиться в отдельном файле таблицы стилей XSLT и будет импортировать таблицы стилей с шаблонами, реализующими операции. Основной шаблон не знает, какие операции реализованы (и не использует <xsl:choose>
С жестко заданными именами).
фактически, если шаблоны добавлены или удалены из импортированных файлов, нет необходимости изменять основной (используя) шаблон. В этом стиле программирования <xsl:apply-templates>
инструкция часто выбирает для шаблоны оформления, которые еще не были написаны, когда был изготовлен основной шаблон.