15

I want to apply a template with a mode that depends on a variable value.

<xsl:variable name="mode" select="@attribute"/>
<xsl:apply-templates mode="{$mode}"/>

I get the error that the stylesheet cannot be compiled. The value of mode should be a QName, but it is "{$mode}".

Is there a possibilty to use modes dependent on variables?

yoozer8
  • 7,361
  • 7
  • 58
  • 93
maria90
  • 269
  • 4
  • 10
  • What you want to do is syntactically illegal, but it is *possible* in XSLT 1.0 to achieve the same effect, using the "template reference" principle that is the foundation for the FXSL library. – Dimitre Novatchev Sep 06 '12 at 12:28
  • Thank you for this idea! I tried to understand it, but I am new at XSLT and don't have much experience with functional programming. For the described case, it is "over-engineered". Maybe, I can use it some times, when I have more experience with it. – maria90 Sep 06 '12 at 14:17
  • maria90, It is enough to know that such technique exists -- then to use it whenever necessary. – Dimitre Novatchev Sep 06 '12 at 14:24

3 Answers3

9

The only option you have to use a certain mode based on an expression is to use

<xsl:choose>
   <xsl:when test="@attribute = 'foo'">
      <xsl:apply-templates mode="bar"/>
   </xsl:when>
   <xsl:otherwise>
      <xsl:apply-templates/>
   </xsl:otherwise>
</xsl:choose>

or the same with an xsl:if. The mode attribute value itself needs to be a QName in XSLT 1.0 respectively in XSLT 2.0 allows a QName or special tokens like #current or #default'. But you can't compute a mode value at run-time.

Martin Honnen
  • 160,499
  • 6
  • 90
  • 110
  • This was my first idea to solve the problem. I wanted to avoid testing specific values of the variable. Nevertheless, I will use this way because FXSL is a bit to heavy for me. – maria90 Sep 06 '12 at 14:20
5

mode is not a valid candidate for Attribute Value Templates (AVT). You simply can't do this.

From the XSLT 2.0 spec:

[Definition: In an attribute that is designated as an attribute value template, such as an attribute of a literal result element, an expression can be used by surrounding the expression with curly brackets ({})].

mode is not designated as AVT in the spec, so ou can't do this.

Sean B. Durkin
  • 12,659
  • 1
  • 36
  • 65
2

I get the error that the stylesheet cannot be compiled. The value of mode should be a QName, but it is "{$mode}".

Is there a possibilty to use modes dependent on variables?

No, this is not supported in any XSLT version -- 1.0, 2.0 or 3.0.

As you are trying in effect to emulate Higher Order Functions (HOF), you may use the underlying principle of FXSL to do this in XSLT 1.0.

FXSL 1.x is a library of templates written in pure XSLT 1.0 that supports/emulates HOF.

Here is a complete solution based on these principles:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:f="http://fxsl.sf.net" exclude-result-prefixes="f">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

   <f:inc/>
   <f:double/>

 <xsl:variable name="vModeInc" select="document('')/*/f:inc[1]"/>
 <xsl:variable name="vModeDouble" select="document('')/*/f:double[1]"/>

 <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match="/*">
  <nums>
    <xsl:apply-templates select="$vModeInc">
      <xsl:with-param name="pNodes" select="node()"/>
    </xsl:apply-templates>
  </nums>
==============
  <nums>
    <xsl:apply-templates select="$vModeDouble">
      <xsl:with-param name="pNodes" select="node()"/>
    </xsl:apply-templates>
  </nums>
 </xsl:template>

 <xsl:template match="f:inc">
   <xsl:param name="pNodes"/>
   <xsl:apply-templates select="$pNodes" mode="incr"/>
 </xsl:template>

 <xsl:template match="f:double">
   <xsl:param name="pNodes"/>
   <xsl:apply-templates select="$pNodes" mode="double"/>
 </xsl:template>

 <xsl:template match="num" mode="incr">
  <num><xsl:value-of select=".+1"/></num>
 </xsl:template>

 <xsl:template match="num" mode="double">
  <num><xsl:value-of select=".*2"/></num>
 </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the following XML document:

<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>

the wanted, correct result is produced -- the nums/num elements processed in one (each) of the two modes available, depending on the variable specified -- $vModeInc (1 added to each value) or $vModeDouble (each value is multiplied by two):

<nums>
   <num>2</num>
   <num>3</num>
   <num>4</num>
   <num>5</num>
   <num>6</num>
   <num>7</num>
   <num>8</num>
   <num>9</num>
   <num>10</num>
   <num>11</num>
</nums>
==============
  <nums>
   <num>2</num>
   <num>4</num>
   <num>6</num>
   <num>8</num>
   <num>10</num>
   <num>12</num>
   <num>14</num>
   <num>16</num>
   <num>18</num>
   <num>20</num>
</nums>
Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
  • +1 That's clever. I have not kept up on FXSL, but have wished I had time to do so. :-) For anybody else who's reading, it's worth your time to trace through the XSLT above and see what it's doing. – LarsH Sep 06 '12 at 13:12
  • @LarsH, Thanks, just read the Extreme Markup Languages paper on FXSL 2 -- it doesn't take too much time. :) – Dimitre Novatchev Sep 06 '12 at 13:37
  • can you give a link to that paper? I googled and found this: http://fxsl.sourceforge.net/ which has a links to 2 papers, both of which are broken. Oh, is this it? http://conferences.idealliance.org/extreme/html/2006/Novatchev01/EML2006Novatchev01.html – LarsH Sep 06 '12 at 14:21
  • @LarsH: This one isn't broken (from my SO profile): http://conferences.idealliance.org/extreme/html/2006/Novatchev01/EML2006Novatchev01.html – Dimitre Novatchev Sep 06 '12 at 14:26