Search code examples
xsltxsl-choose

XSLT - How to refer to a current node value using xsl:choose?


I try to create a variable, which I can use in a later template:

<xsl:variable name="fc">
    <xsl:choose>
        <xsl:when test="self::node()='element1'">gray</xsl:when>
        <xsl:otherwise>red</xsl:otherwise>
    </xsl:choose>
</xsl:variable>

Unfortunately it does not work.

<xsl:template match="element1">
    <h1><font color="{$fc}"><xsl:value-of select="self::node()"/></font></h1>
</xsl:template>

What am I doing wrong?

Here is the extensive code:

XML:

<root 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.test.com scheme.xsd" xmlns="http://www.test.com" xmlns:tst="http://www.test.com">
 <elementA>
    <elementB tst:name="name">
        <elementC tst:name="name">
            <element1> Test1 </element1>
            <element2> Test2 </element2>
         </elementC >
    </elementB> 
  </elementA>    
</root>

All the elements are qualified and part of the namespace "http://www.test.com".

XSLT:

<xsl:template match="/">
<html>
<body><xsl:apply-templates select="tst:root/tst:elementA/tst:elementB/tst:elementC/tst:element1"/>
</body>
</html>

</xsl:template>
<xsl:variable name="var_fc">
<xsl:choose>
    <xsl:when test="local-name(.)='tst:element1'">gray</xsl:when>
    <xsl:otherwise>red</xsl:otherwise>
</xsl:choose>
</xsl:variable>

<xsl:template match="tst:element1">
<h2><font color="{$var_fc}"><xsl:value-of select="self::node()"/></font></h2>
</xsl:template>

As a result, element1 should turn gray, but it always turn red.


Solution

  • You can't use a variable for this, as the content of an xsl:variable is evaluated just once at definition time, whereas you want to evaluate some logic every time the variable is referenced, in the current context at the point of reference.

    Instead you need a template, either a named one:

    <xsl:template name="fc">
      <xsl:choose>
        <xsl:when test="local-name()='element1'">gray</xsl:when>
        <xsl:otherwise>red</xsl:otherwise>
      </xsl:choose>
    </xsl:template>
    

    or (better) a pair of matching templates with a mode, to let the template matcher do the work:

    <!-- match any node whose local name is "element1" -->
    <xsl:template mode="fc" match="node()[local-name() = 'element1']">gray</xsl:template>
    
    <!-- match any other node -->
    <xsl:template mode="fc" match="node()">red</xsl:template>
    

    When you want to use this logic:

    <h1>
      <font>
        <xsl:attribute name="color">
          <xsl:apply-templates select="." mode="fc" />
        </xsl:attribute>
    

    Seeing as you have the tst prefix mapped in your stylesheet you could check the name directly instead of using the local-name() predicate:

    <xsl:template mode="fc" match="tst:element1">gray</xsl:template>
    <xsl:template mode="fc" match="node()">red</xsl:template>