gray gray gray

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

1.9k views Asked by At

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.

5

There are 5 answers

0
Ian Roberts On BEST ANSWER

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>
1
Andreas On

XSLT variables are designed not to be changeable. Actually they could be named constants. If your variable fc is created global, it will use the root element for choose. You have to use choose in the actual template to be tested against the current element. If you want to have "red" and "gray" defined only once, create two variables with just that text content and use these instead the plain text in the choose.

0
Joel M. Lamsen On

Maybe it is a typo:

<xsl:when test=self::node()='element1'">gray</xsl:when>

should be:

<xsl:when test="self::node()='element1'">gray</xsl:when>

there is a missing quote.

1
Martin Honnen On

I think instead of test="self::node()='element1'" you want test="self::element1" or test="local-name(.) = 'element1'".

0
Michael Kay On

A couple of other errors in your code:

(1) self::node() = 'element1'

tests whether the content of the element is "element1", not whether its name is "element1"

(2) local-name(.)='tst:element1'

will never be true because the local name of a node never contains a colon.

Experienced users would often write this code using template rules:

<xsl:template mode="var_fc" match="tst:element1">gray</xsl:template>
<xsl:template mode="var_fc" match="*">red</xsl:template>

and then

<xsl:apply-templates select="." mode="var_fc"/>