Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

xslt variable scope and its usage

Tags:

xslt

I am learning xslt and had one question about how can i use xslt variable in diff. for each loop. I know xslt isn't a procedural language so variable declared in for loop cannot be accessed in another loop. But is there any way I can just declare global variable then assign some value in first for loop and use that variable in second for loop?

Any ideas would be highly appreciated.

Thanks

like image 489
user509755 Avatar asked Feb 12 '12 15:02

user509755


1 Answers

is there any way I can just declare global variable then assign some value in first for loop and use that variable in second for loop?

The way to assign value to an xsl:variable (of course this is only initialization) from within an xsl:for-each, is to include the xsl:for-each in the body of the variable.

Here is a complete example:

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

 <xsl:template match="/*">
     <xsl:variable name="vMax">
       <xsl:for-each select="num">
        <xsl:sort data-type="number" order="descending"/>

        <xsl:if test="position() = 1">
         <xsl:value-of select="."/>
        </xsl:if>
       </xsl:for-each>
     </xsl:variable>

     Values close to the maximum:
<xsl:text/>

       <xsl:for-each select="num">
        <xsl:if test="not($vMax - . > 3) ">
         <xsl:value-of select="."/>
         <xsl:text>&#xA;</xsl:text>
        </xsl:if>
       </xsl:for-each>
 </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>

...it first defines a vMax variable that gets its value from the xsl:for-each contained in its body.

Then the vMax variable is used in the second xsl:for-each to output all numbers that are "close" to the so computed maximum.

The wanted, correct result is produced:

     Values close to the maximum:
07
08
09
10

It is also possible to simulate "assigning" a variable with different values by using a recursively called named template and pass the "new value" as parameter to the called template.

Here is an example showing this technique. Here we are calculating the maximum of values, contained in nodes of a node-set. Every time we access the next node in the node-set, the current maximum is compared to this value and if necessary the new maximum becomes the value of the next node. We then call the same template recursively, passing as the value of the current maximum the new maximum:

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

 <xsl:template match="/*">
  <xsl:call-template name="max">
    <xsl:with-param name="pList" select="*"/>
  </xsl:call-template>
 </xsl:template>

 <xsl:template name="max">
   <xsl:param name="pMax" select="-99999999"/>
   <xsl:param name="pList"/>

   <xsl:choose>
     <xsl:when test="$pList[1]">
       <xsl:variable name="vnewMax" select=
       "$pMax * ($pMax >= $pList[1])
       +
        $pList[1] * not($pMax >= $pList[1])
       "/>

       <xsl:call-template name="max">
        <xsl:with-param name="pMax" select="$vnewMax"/>
        <xsl:with-param name="pList" select="$pList[position() > 1]"/>
       </xsl:call-template>
     </xsl:when>
     <xsl:otherwise>
       <xsl:value-of select="$pMax"/>
     </xsl:otherwise>
   </xsl:choose>
 </xsl:template>
</xsl:stylesheet>

When this transformation is applied to the same XML document (above), the wanted, correct result is produced:

10
like image 107
Dimitre Novatchev Avatar answered Oct 06 '22 09:10

Dimitre Novatchev