XSLT Call-Template name attribute

2019-07-21 20:49发布

问题:

It seems as if I can't use an Xpath in the name attribute of the call-template element. How can I get around this? Any help/thoughts would be awesome!

<xsl:for-each select="child::knomaddb/Content/Videos">
        <xsl:result-document method="xhtml" href="{local-name()}.html">
            <html>
                <body>
                    <h1>Knomad</h1>
                    <h2>{local-name()} Videos</h2>
                    <table border="1">
                        <tr bgcolor="#9acd32">
                            <th>Title</th>
                            <th>Video</th>
                            <th>Description</th>
                            <th>Comments</th>
                        </tr>
                        <xsl:for-each select="Video">
                            <xsl:call-template name="{ancestor::local-name()}"/>
                        </xsl:for-each>
                    </table>
                </body>
            </html>
        </xsl:result-document>
    </xsl:for-each>

回答1:

It seems as if I cant use an Xpath in the name attribute of the call-template element. How can I get around this?

Good question, +1.

You can't. But you can use instead <xsl:apply-templates>.

Here is a quick demo:

<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:double="double" xmlns:incr="incr" xmlns:my="my:my"
exclude-result-prefixes="double incr my"
>
  <xsl:output method="text"/>

   <double:double/>
   <incr:incr/>

   <xsl:variable name="vFuncDouble"
        select="document('')/*/double:*[1]"/>

   <xsl:variable name="vFuncIncr"
        select="document('')/*/incr:*[1]"/>

   <xsl:function name="my:double">
     <xsl:param name="arg1" />

      <xsl:sequence select="2*$arg1"/>
   </xsl:function>

   <xsl:function name="my:incr">
     <xsl:param name="arg1" />

      <xsl:sequence select="1+$arg1"/>
   </xsl:function>

    <xsl:template name="double" match="double:*">
      <xsl:param name="arg1"/>

      <xsl:sequence select="my:double($arg1)"/>
    </xsl:template>

    <xsl:template name="incr" match="incr:*">
      <xsl:param name="arg1"/>

      <xsl:sequence select="my:incr($arg1)"/>
    </xsl:template>

    <xsl:function name="my:apply">
      <xsl:param name="pFun" as="element()"/>
      <xsl:param name="arg1"/>

      <xsl:apply-templates select="$pFun">
        <xsl:with-param name="arg1" select="$arg1"/>
      </xsl:apply-templates>
    </xsl:function>

    <xsl:template match="/">
     <xsl:sequence select="my:apply($vFuncIncr, my:apply($vFuncDouble,2))"/>
    </xsl:template>
</xsl:stylesheet>

When this transformation is applied on any XML document (not used), the wanted result is produced:

5

Do note:

One can pass as parameter (the first argument) to my:apply() any "function" and my:apply() will apply it to its second argument.

Using this same principle the FXSL library implemented Higher Order Functions (HOFs) in XSLT 1.0 and XSLT 2.0 -- read more here.

In the forthcoming XPath 3.0 functions are for the first time first class objects in the Xpath Data Model (XDM).



回答2:

This is by design. xsl:call-template is defined as follows:

<!-- Category: instruction -->
<xsl:call-template
  name = qname>
  <!-- Content: xsl:with-param* -->
</xsl:call-template>

The name attribute must be a qualified name, not an XPath expression.

Sources:

  • XSL Transformations (XSLT) Version 2.0
  • Namespaces in XML 1.0