XSLT call-шаблон с динамическим QName?
я обыскал все вокруг, чтобы найти решение моей проблемы, но я получил еще больше вопросов...
рассмотрим следующий XML-код:
<dynamicStuff>
<dyn id="name1">...</dyn>
<dyn id="name2">...</dyn>
<dyn id="name3">...</dyn>
<dyn id="name4">...</dyn>
</dynamicStuff>
и предположим, что у меня есть файл XSLT следующим образом:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template name="name1">
...
</xsl:template>
<xsl:template name="name2">
...
</xsl:template>
<xsl:template name="name3">
...
</xsl:template>
<xsl:template name="name4">
...
</xsl:template>
</xsl:stylesheet>
то, что я хочу сделать, это из второго файла XSLT динамически определить, какой шаблон вызвать с чем-то вроде этого:
<xsl:variable name="templateName">
<xsl:value-of select="dyn/@id"/>
</xsl:variable>
<xsl:call-template name="$templateName"/>
к сожалению, он не работает, поверьте мне, когда я говорю, что я пробовал много разных вещей, хотя это звучит так просто это не работает...
Я что-то пропустила?
Edit:
я успешно сделал следующее:
<xsl:template name="staticName">
<xsl:param name="id" />
<xsl:if test="$id = 'name1'">....</xsl:if>
<xsl:if test="$id = 'name2'">....</xsl:if>
...
</xsl:template>
вызов таким образом:
<xsl:call-template name="staticName">
<xsl:with-param name="id" select="@id"/>
</xsl:call-template>
иглы, чтобы сказать, как неудобно это... прежде всего, мой код будет привязан к этому staticName (представьте, что мне нужно сделать этот вызов в дюжине файлов)... во-вторых, у меня будет куча (un)связанного контента внутри того же шаблона, когда он может будьте более отделены... кошмар для обновления системы u.u
это то, что я хочу, но не так, как мне нужно...
заранее спасибо за любой свет на этот вопрос!
5 ответов
от http://www.w3.org/TR/xslt#named-templates
значение - это QName, который расширен, как описано в [2.4 квалифицированных Имена].
это означает, что это не выражение и не AVT.
явно xsl:call-template
инструкции прекрасны, будь то логические инструкции или соответствие шаблону, как:
<xsl:template match="dyn[@id='name1']" mode="dynamic">
<xsl:call-template name="name1"/>
</xsl:template>
другой подход называется шаблоном...
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable name="vTemplate" select="document('')/*/xsl:template"/>
<xsl:template match="dyn">
<xsl:apply-templates select="$vTemplate[@name = current()/@id]"/>
</xsl:template>
<xsl:template match="xsl:template[@name='name1']"
name="name1"> one </xsl:template>
<xsl:template match="xsl:template[@name='name2']"
name="name2"> two </xsl:template>
<xsl:template match="xsl:template[@name='name3']"
name="name3"> three </xsl:template>
<xsl:template match="xsl:template[@name='name4']"
name="name4"> four </xsl:template>
</xsl:stylesheet>
выход:
one two three four
Примечание: потому что эта техника использует
document('')
чтобы обработать XSLT, а не исходный XML-файл, исходный обрабатываемый документ недоступен в именованных шаблонах. Однако, вы можете явно передавать current()
как параметр к шаблонам если нужно:
<xsl:template match="dyn">
<xsl:apply-templates select="$vTemplate[@name = current()/@id]">
<xsl:with-param name="current" select="current()"/>
</xsl:apply-templates>
</xsl:template>
при необходимости $current
можно использовать для доступа к первоначальной документ:
<xsl:template match="xsl:template[@name='name1']" name="name1">
<xsl:param name="current"/>
<xsl:value-of select="$current/@id"/>
<xsl:text> becomes one</xsl:text>
</xsl:template>
при необходимости $current
может быть восстановлен как текущий узел с помощью for-each
:
<xsl:template match="xsl:template[@name='name2']" name="name2">
<xsl:param name="current"/>
<xsl:for-each select="$current">
<xsl:value-of select="@id"/>
<xsl:text> becomes two</xsl:text>
</xsl:for-each>
</xsl:template>
Если у вас есть только конечное число возможных шаблонов, будет ли работать использование xsl if construct для выбора того, что делать в главном шаблоне?
<xsl:if test="$templateName = 'name1'">
<xsl:call-template name="name1"/>
</xsl:if>
обычно, когда кто-то пытается это сделать, это означает, что они не знают о полной мощности xsl:apply-templates. Способ динамической отправки в XSLT-использовать xsl: apply-templates. Например, для указанной проблемы напишите правила шаблона, такие как
<xsl:template match="dyn[@id='name1']">...</xsl:template>
<xsl:template match="dyn[@id='name2']">...</xsl:template>
<xsl:template match="dyn[@id='name3']">...</xsl:template>
и затем использовать <xsl:apply-templates select="dyn"/>
для выполнения отправки.
то, что вы пытаетесь, напрямую невозможно, но почему бы просто не сопоставить на id
значение атрибута в первую очередь? Если вам абсолютно нужна косвенность вызываемого шаблона, то вызовите его из шаблона, который соответствует id
(см. name4
ниже):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<t><xsl:apply-templates select="dynamicStuff/dyn"/></t>
</xsl:template>
<!-- match on attribute value -->
<xsl:template match="dyn[@id='name1']">name1</xsl:template>
<xsl:template match="dyn[@id='name2']">name2</xsl:template>
<xsl:template match="dyn[@id='name3']">name3</xsl:template>
<xsl:template match="dyn[@id='name4']">
<xsl:call-template name="name4"/>
</xsl:template>
<!-- named templates -->
<xsl:template name="name1">name1</xsl:template>
<xsl:template name="name2">name2</xsl:template>
<xsl:template name="name3">name3</xsl:template>
<xsl:template name="name4">name4</xsl:template>
</xsl:stylesheet>
вход:
<dynamicStuff>
<dyn id="name1">...</dyn>
<dyn id="name2">...</dyn>
<dyn id="name3">...</dyn>
<dyn id="name4">...</dyn>
</dynamicStuff>
выход:
<t>name1name2name3name4</t>
Если вы используете старый Saxon-B или более новый Saxon-PE или Saxon-EE в качестве процессора XSLT, вы можете использовать расширение saxon для достижения динамических вызовов шаблонов:
<xsl:variable name="templateName">
<xsl:value-of select="dyn/@id"/>
</xsl:variable>
<saxon:call-template name="{$templateName}"/>
Не забудьте объявить пространство имен saxon в элементе xsl-stylesheet:
<xsl:stylesheet xmlns:saxon="http://saxon.sf.net/" [...] >