Variables in xpath expressions

20,187

Solution 1

<xsl:variable name="dayOfWeekIndex">    
    <xsl:choose>    
        <xsl:when test="lower-case($dayOfWeek) = 'monday'">
            <xsl:value-of select="number(1)" />
        </xsl:when>
        ....

An <xsl:variable> with content but no as attribute will set the variable to a "temporary tree", not a number, so a predicate [$dayOfweekIndex] is treated as a boolean predicate rather than a restriction on the nodes' position(). You need to add as="xs:integer" to the xsl:variable tag to force the variable to have the correct type.

Alternatively, use a select instead, with the if construct in XPath 2.0:

<xsl:variable name="dayOfWeekIndex" as="xs:integer" select="
    if (lower-case($dayOfWeek) = 'monday') then 1 else
    if (lower-case($dayOfWeek) = 'tuesday') then 2 else
    .....
    if (lower-case($dayOfWeek) = 'sunday') then 7 else
    0" />

Solution 2

It matters how you set up the variable or parameter obviously e.g. with

<xsl:variable name="index" select="4"/>
<xsl:apply-templates select="data/contents[$index]/content"/>

it should work (i.e. process the fourth contents), with

<xsl:variable name="index">4</xsl:variable>
<xsl:apply-templates select="data/contents[$index]/content"/>

it doesn't work as the predicate expression is not of type xs:integer, it is a non empty sequence of nodes.

Solution 3

As others have noticed, specifying the type of a variable really matters in XSLT 2.0.

In addition to this, this transformation shows how to use an XPath one-liner to produce the wanted result:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema">
 <xsl:output method="text"/>

 <xsl:variable name="vWeekDays" as="xs:string+" select=
 "('monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday')"/>


 <xsl:template match="/">
  <xsl:variable name="vdayOfWeek" select="'Friday'"/>

  <xsl:sequence select="index-of($vWeekDays, lower-case($vdayOfWeek))"/>
 </xsl:template>
</xsl:stylesheet>

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

5
Share:
20,187
pethel
Author by

pethel

Updated on April 13, 2020

Comments

  • pethel
    pethel about 4 years

    Is it not posssible to use xsl:variables in xpath expressions? I am sure that my variable has the correct value. Have tried it both as String and number. The first one works but the second one selects all contents nodes and not just the one with index 4.

    <xsl:apply-templates select="data/contents[4]/content" >
    <xsl:apply-templates select="data/contents[$myVariable]/content" >
    

    edit

        <xsl:variable name="dayOfWeekIndex">    
            <xsl:choose>    
                <xsl:when test="lower-case($dayOfWeek) = 'monday'">
                    <xsl:value-of select="number(1)" />
                </xsl:when>
                <xsl:when test="lower-case($dayOfWeek) = 'tuesday'">
                    <xsl:value-of select="number(2)" />
                </xsl:when>
                <xsl:when test="lower-case($dayOfWeek) = 'wednesday'">
                    <xsl:value-of select="number(3)" />
                </xsl:when>
                <xsl:when test="lower-case($dayOfWeek) = 'thursday'">
                    <xsl:value-of select="number(4)" />
                </xsl:when>
                <xsl:when test="lower-case($dayOfWeek) = 'friday'">
                    <xsl:value-of select="number(5)" />
                </xsl:when>
                <xsl:when test="lower-case($dayOfWeek) = 'saturday'">
                    <xsl:value-of select="number(6)" />
                </xsl:when>
                <xsl:when test="lower-case($dayOfWeek) = 'sunday'">
                    <xsl:value-of select="number(7)" />
                </xsl:when>
            </xsl:choose>   
        </xsl:variable>