tags:

views:

558

answers:

4

When I try to use the code below I get a duplicate variable error because variables are immutable. How do I set the smaller of the two variables ($nextSubPartPos,$nextQuestionStemPos) as my new variable ($nextQuestionPos)?

  <xsl:variable name="nextQuestionPos"/>
  <xsl:choose>
   <xsl:when test="$nextSubPartPos &lt; $nextQuestionStemPos">
    <xsl:variable name="nextQuestionPos" select="$nextSubPartPos"/>
   </xsl:when>
   <xsl:otherwise>
    <xsl:variable name="nextQuestionPos" select="$nextSubPartPos"/>
   </xsl:otherwise>
  </xsl:choose>
+1  A: 

Variables in XSLT are immutable. This has tripped me up so many times.

David Kemp
Is there any way to get the larger of the two?
joe
@joe, yes. Replace min with max in my answer or < and > in the question
phihag
Yes, but that's a new question. :) See my answer, it provides more compact and ellegant XPath 1.0 solution and two different XPath 2.0 solutions.
Dimitre Novatchev
+2  A: 

Don't close the xsl:variable node in the first line. That is, take the / out of it, then put an </xsl:variable> after </xsl:choose>. Next, change the <xsl:variable> nodes inside the choose to <xsl:value-of> nodes.

That is, you want to set the value of the variable with the choose. There are two ways to set the value of a variable. One is the select attribute, the other is the inner text of the node.

<xsl:variable name="nextQuestionPos">
    <xsl:choose>
         <xsl:when test="$nextSubPartPos &lt; $nextQuestionStemPos">
               <xsl:value-of select="$nextSubPartPos"/>
         </xsl:when>
         <xsl:otherwise>
               <xsl:value-of select="$nextSubPartPos"/>
         </xsl:otherwise>
    </xsl:choose>
</xsl:variable>
nsayer
+1  A: 

Just use the min function:

<xsl:variable name="a" select="42" />
<xsl:variable name="b" select="23" />
<xsl:variable name="x" select="min(($a,$b))" />

In your example, replace the entire code with:

<xsl:variable name="nextQuestionPos" select="min(($nextSubPartPos,$nextQuestionStemPos))" />

Saxon implements min in the global namespace. Other processors may require a namespace, the correct one (usually denoted fn) is http://www.w3.org/2005/02/xpath-functions .

phihag
This solves the immediate problem, but doesn't address the larger question of how to implement complex logic - perhaps logic too complex for XPath - to form a variable's value.
nsayer
+2  A: 

A compact XPath 1.0 expression that evaluates to the smaller value is:

    $v1*($v2 >= $v1) + $v2*($v1 > $v2)

where the $v1 and $v2 variables contain the values to be compared.

So, an elegant one-liner XSLT 1.0 solution will look like this:

    <xsl:variable name="v3" select="$v1*($v2 >= $v1) +$v2*($v1 > $v2)"/>

It is easier to define a variable as required in XSLT 2.0:

One can use either the following (more readable) one-liner:

    if($v2 gt $v1)
                then $v1
                else $v2

Or the more compact:

    min(($v1, $v2))

Dimitre Novatchev