16

我不知道这是否可能,但我想知道如何做到这一点......

假设我们有以下 XSL:

<xsl:template name="foo">
  Bla bla bla
</xsl:template>
...
<xsl:template name="bar">
  Bla bla bla
</xsl:template>
...
<xsl:template match="/">
  <xsl:if test="$templateName='foo'">
    <xsl:call-template name="foo"/>
  </xsl:if>
  <xsl:if test="$templateName='bar'">
    <xsl:call-template name="bar"/>
  </xsl:if>
</xsl:template>

是否可以更改 XSL 以读取类似...

<xsl:template match="/">
  <xsl:call-template name="$templateName"/>
</xsl:template>
4

7 回答 7

13

不可能完全按照您的描述,但是如果您希望能够在运行时根据您在其他地方设置的某些值选择模板,那么有一个技巧可以做到这一点。这个想法是让您的命名模板也以不同的模式匹配具有相应名称的节点(这样它就不会弄乱您的正常转换),然后匹配。例如:

<xsl:stylesheet ... xmlns:t="urn:templates">

  <!-- Any compliant XSLT processor must allow and ignore any elements 
       not from XSLT namespace that are immediate children of root element -->
  <t:templates>
    <t:foo/>
    <t:bar/>
  </t:templates>

  <!-- document('') is the executing XSLT stylesheet -->     
  <xsl:variable name="templates" select="document('')//t:templates" />

  <xsl:template name="foo" match="t:foo" mode="call-template">
    Bla bla bla
  </xsl:template>

  <xsl:template name="bar" match="t:foo" mode="call-template">
    Bla bla bla
  </xsl:template>

  <xsl:template match="/">
    <xsl:variable name="template-name" select="..." />
    <xsl:apply-templates select="$templates/t:*[local-name() = $template-name]"
                         mode="call-template"/>
  </xsl:template>

请注意,您可以使用<xsl:with-param>in <xsl:apply-templates>,因此您可以使用它来做所有可以使用普通<xsl:call-template>.

此外,上面的代码比您可能需要的要长一些,因为它试图避免使用任何 XSLT 扩展。如果您的处理器支持exslt:node-set(),那么您可以直接使用 生成节点<xsl:element>,并使用node-set()将生成的树片段转换为普通节点以进行匹配,而无需document('')hack。

有关更多信息,请参阅FXSL - 它是基于此概念的 XSLT 函数式编程库。

于 2009-08-05T22:09:58.537 回答
6

不,这是不可能的,也不是直接可能的。调用约定是:

<xsl:call-template name="QName" />

QName定义为

QName ::= PrefixedName | UnprefixedName

PrefixedName   ::= Prefix ':' LocalPart
UnprefixedName ::= LocalPart

Prefix         ::= NCName
LocalPart      ::= NCName

基本上这归结为“只有字符,没有表达式”。正如其他答案所强调的那样,实际上有一些方法可以做一些等效的事情,但是直接的方法/天真的方法是行不通的。

于 2009-08-05T16:00:37.333 回答
3

供任何人将来参考:

这是一个基于 Pavel Minaev 回答的工作示例。我没有原创的想法。;-) 我将它切换为使用他所描述的 msxml:node-set (或多或少),以便它在.NET中工作。

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" version="1.0">
    <xsl:variable name="templates">
        <templates>
            <foo />
            <bar />
        </templates>
    </xsl:variable>
    <xsl:template name="foo" match="foo" mode="call-template">
        <FooElement />
    </xsl:template>
    <xsl:template name="bar" match="bar" mode="call-template">
        <BarElement />
    </xsl:template>
    <xsl:template match="/">
        <Root>
            <xsl:variable name="template-name">bar</xsl:variable> <!-- Change this to foo to get the other template. -->
            <xsl:apply-templates select="msxsl:node-set($templates)/*/*[local-name() = $template-name]" mode="call-template" />
        </Root>
    </xsl:template>
</xsl:stylesheet>
于 2013-07-18T16:00:04.207 回答
2

我想我或多或少和你有同样的问题。我有一个“外部”模板,并想根据运行时设置的某些变量调用不同的“内部”模板。我通过谷歌搜索找到了你的问题,寻找一种动态的<xsl:call-template>. 我通过使用解决了它<xsl:apply-templates>,如下所示。

输入 XML(在运行时生成)包含以下内容:

<template name="template_name_1"/>

“外部”模板中的 XSL 具有:

<xsl:apply-templates select="template"/>

select="template"此 apply-templates 中的 指<template>输入 XML 中的标签)

name最后,作为XML 中属性值的结果,我想包含的“内部”模板如下所示:

<xsl:template match="template[@name='template_name_1']">
    <!-- XSL / XHTML goes here -->
</xsl:template>

(同样,thematch="template[@name='xyz']"指的是前一个select="template",然后指的是输入 XML 中的<template>标记及其属性)name

通过这种方式,我可以简单地通过输入 XML 控制来动态地“调用”模板。

这可能与您尝试解决的问题不同,但我认为它非常接近,并且比本页其他地方提到的 FSXL 解决方案简单得多。

于 2013-03-29T19:22:57.163 回答
2

更新:下面的链接已更新为指向 web.archive.org——不幸的是,IDEALLIANCE 已使所有Exteme Markup Languages会议记录不可用……在适当的时候,我将为这两篇文章找到一个更永久的位置。


这是在FXSL中实现的。

对 FXSL 的主要原理有很好的解释。

请看以下两篇文章:

使用 FXSL 库在 XSLT 中进行函数式编程”(针对 XSLT 1.0),(PDF),位于:

http://web.archive.org/web/20070710091236/http://www.idealliance.org/papers/extreme/proceedings/xslfo-pdf/2003/Novaatchev01/EML2003Novatatchev01.pdf

(HTML) 在:

http://conferences.idealliance.org/extreme/html/2003/Novaatchev01/EML2003Novaatchev01.html



使用 XSLT 2.0 和 FXSL 进行高阶函数式编程”(PDF)位于:

http://web.archive.org/web/20070222111927/http://www.idealliance.org/papers/extreme/proceedings/xslfo-pdf/2006/Novaatchev01/EML2006Novatatchev01.pdf

(HTML) 网址: http ://conferences.idealliance.org/extreme/html/2006/Novaatchev01/EML2006Novaatchev01.html



使用 FXSL,我已经能够轻松而优雅地解决许多问题,这些问题似乎“对于 XSLT 来说是不可能的”。在这里可以找到很多例子。

于 2009-08-06T03:53:39.877 回答
0

这个如何?:

  <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

      <xsl:template match="xsl:template[@name='foo']" name="foo">
    Bla bla bla foo
      </xsl:template>

      <xsl:template match="xsl:template[@name='bar']" name="bar">
    Bla bla bla bar
      </xsl:template>

      <xsl:template match="/">
        <xsl:variable name="templateName" select="'bar'"/>
        <xsl:apply-templates select="document('')/*/xsl:template[@name=$templateName]"/>
        <xsl:apply-templates select="document('')/*/xsl:template[@name='foo']"/>
      </xsl:template>

    </xsl:stylesheet>

您可以使用变量来简化模板的“调用”,类似于之前的贡献中所述:

<xsl:variable name="templates" select="document('')/*/xsl:template"/> 

<xsl:apply-templates select="$templates[@name=$templateName]"/>
<xsl:apply-templates select="$templates[@name='foo']"/>

注意 optional<xsl:with-param>可以照常使用。

于 2015-02-11T15:28:51.257 回答
0

谢谢@Pavel,@Dimitre 的出色回答。这是另一个工作示例,它基本上回收了@Pavel 的方法以供将来参考...

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  

  <xsl:variable name="templates">
    <xsl:for-each select="('foo','bar')">
      <xsl:element name="{.}"/>
    </xsl:for-each>
  </xsl:variable>
  
  <xsl:template name="foo" match="foo" mode="call-template">
    Foo foo foo
  </xsl:template>
  
  <xsl:template name="bar" match="bar" mode="call-template">
    Bar bar bar
  </xsl:template>
  
  <xsl:template match="/">
  
    <xsl:for-each select="('bar','foo','foo','bar')">
      <xsl:variable name="template-name" select="." />
      <xsl:apply-templates select="$templates/*[local-name() = $template-name]"  mode="call-template"/>
    </xsl:for-each>
    
    
  </xsl:template>

</xsl:stylesheet>
于 2021-11-02T15:25:08.647 回答