代码之家  ›  专栏  ›  技术社区  ›  Paulo Santos

如何基于变量调用命名模板?

  •  14
  • Paulo Santos  · 技术社区  · 15 年前

    我不知道是否有可能,但我想知道怎么做…

    假设我们有以下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>
    
    6 回复  |  直到 9 年前
        1
  •  6
  •   Tomalak    15 年前

    不,这是 不可能 不直接可能。呼叫约定是:

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

    在哪里 QName is defined as :

    QName ::= PrefixedName | UnprefixedName
    
    PrefixedName   ::= Prefix ':' LocalPart
    UnprefixedName ::= LocalPart
    
    Prefix         ::= NCName
    LocalPart      ::= NCName
    

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

        2
  •  11
  •   Pavel Minaev    15 年前

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

    <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> 在里面 <xsl:apply-templates> 所以你可以用这个做任何事情,你可以用一个普通的 <xsl:call-template> .

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

    有关详细信息,请参阅 FXSL -它是一个基于这个概念的XSLT函数编程库。

        3
  •  3
  •   Tom Winter    11 年前

    供将来参考:

    下面是一个基于PavelMinaev答案的工作示例。我这方面没有什么独到的想法。;-)我将它切换为使用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>
    
        4
  •  2
  •   Dimitre Novatchev    15 年前

    更新 :下面的链接已更新为指向web.archive.org——不幸的是,IDEAlliance已经 exteme标记语言 会议进程不可用… 在适当的时候,我会为这两篇文章找到一个更永久的位置。


    这是在 FXSL .

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

    见以下两条:

    使用fxsl库在xslt中进行函数编程 “(对于XSLT1.0),(pdf)网址:

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

    (HTML)在:

    http://conferences.idealliance.org/extreme/html/2003/Novatchev01/EML2003Novatchev01.html



    使用xslt 2.0和fxsl进行高阶函数编程 “(PDF)AT:

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

    (HTML)在: http://conferences.idealliance.org/extreme/html/2006/Novatchev01/EML2006Novatchev01.html



    使用fxsl,我已经能够轻松、优雅地解决许多问题,这些问题对于xslt来说似乎是“不可能的”。我们可以找到很多例子 here .

        5
  •  2
  •   Coder    11 年前

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

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

    <template name="template_name_1"/>
    

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

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

    (The select="template" 在此应用模板中,引用 <template> 输入XML中的标记)

    最后是“内部”模板,作为 name 我的XML中的属性如下:

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

    (再一次, match="template[@name='xyz']" 指前一个 选择“模板” 然后依次是 <模板& GT; 标签及其 名称 输入XML中的属性)

    通过这种方式,我可以通过简单地从输入XML控制一个动态的“称为”模板。

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

        6
  •  0
  •   Pavel Novy    9 年前

    这个怎么样?:

      <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']"/>
    

    请注意,可选 <xsl:with-param> 可以像往常一样使用。