Применение различных шаблонов 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> инструкция часто выбирает для шаблоны оформления, которые еще не были написаны, когда был изготовлен основной шаблон.


связался с режим на элемент элемент.