XSL -- Global Variables

L

Loopy

I'm learning XML and XSL at the moment, but I still can't get my head
around the concept of non-updatable variables. I know we can use
recursion to cycle through a data structure and get the sum (say) of a
list of numbers, or a concatination of a set of strings (again,
example), but if I wanted to, for example, keep that value available
for another template later on to use, I can't see how I could do that.

Let me give a better example. I have written and template which is
called "FindMin" that cycles through a tree that finds the minimum. I
have checked the code and, when it it does go through all of the
subtrees and finds the minimum. However, it will only find the minimum
of each of the subtrees, since I cannot keep a global track of the
smallest value, since when I propagate up the tree, I will lose that
value. How could I rectify this?

Here's the code I've written. It may be a bit crude, but that's
because I've been messing around with it. Min and Path are declared as
an empty string (Min) and the root node of the tree in question at
first call.

<xsl:template name="FindMin">
<xsl:param name="Min"/>
<xsl:param name="Path"/>
<xsl:for-each select="./*">
<xsl:choose>
<xsl:when test="@value &lt; $Min">
<!-- Call template with updated min and path -->
<xsl:call-template name="FindMin">
<xsl:with-param name="Min" select="@value"/>
<xsl:with-param name="Path" select="."/>
</xsl:call-template>
</xsl:when>
<xsl:eek:therwise>
<!-- Call template with updated path only -->
<xsl:call-template name="FindMin">
<xsl:with-param name="Min" select="$Min"/>
<xsl:with-param name="Path" select="."/>
</xsl:call-template>
</xsl:eek:therwise>
</xsl:choose>
</xsl:for-each>


The tree I am using for this test is:

<node value="10">
<node value="15"/>
<node value="5">
<node value="7">
<node value="9"/>
<node value="8"/>
</node>
<node value="11"/>
</node>
</node>

Any ideas any one? I'm sure you've had this question before, but most
answers I've checked seem to use Microsoft's XML variation, which I'm
trying to avoid.

Regards

Johnny Ooi
 
J

Joris Gillis

I'm learning XML and XSL at the moment, but I still can't get my head
around the concept of non-updatable variables. I know we can use
recursion to cycle through a data structure and get the sum (say) of a
list of numbers, or a concatination of a set of strings (again,
example), but if I wanted to, for example, keep that value available
for another template later on to use, I can't see how I could do that.

Let me give a better example. I have written and template which is
called "FindMin" that cycles through a tree that finds the minimum. I
have checked the code and, when it it does go through all of the
subtrees and finds the minimum. However, it will only find the minimum
of each of the subtrees, since I cannot keep a global track of the
smallest value, since when I propagate up the tree, I will lose that
value. How could I rectify this?

Here's the code I've written. It may be a bit crude, but that's
because I've been messing around with it. Min and Path are declared as
an empty string (Min) and the root node of the tree in question at
first call.

Hi,

Variables or parameters are indeed non-updateble in XSLT 1.0 and AFAIK there's nothing you can do about. But often, you can get around it by carefully overthinking the problem and redesigning the solution. Encapsulating 'xsl:call-template' with a variable might bring a solution in some cases.

I know that finding a solution to your specific example problem is not the reason for your post, but I'll put my solution here nonetheless:

<xsl:template name="FindMin">
<xsl:param name="Min">9999</xsl:param>
<xsl:choose>
<xsl:when test="count(//*[@value &lt; $Min]) &gt; 0">
<xsl:call-template name="FindMin">
<xsl:with-param name="Min" select="//*[@value &lt; $Min]/@value"/>
</xsl:call-template>
</xsl:when>
<xsl:eek:therwise>
<xsl:value-of select="$Min"/>
</xsl:eek:therwise>
</xsl:choose>
</xsl:template>


regards,
 
J

Johnny Ooi

Thanks for the code, it does the job. Two questions. First, if I wanted
to pass this to another template, I would place a call to the template
in the <xsl:eek:therwise> tag, correct? Second, could you step through the
code for me so I understand how the execution flows through. I'm using
the XSLT engine provided by Altova and that doesn't exactly provide a
friendly debug environment. :p

Johnny
 
J

Joris Gillis

Hi,
Thanks for the code, it does the job. Two questions. First, if I wanted
to pass this to another template, I would place a call to the template
in the <xsl:eek:therwise> tag, correct?

You could, But I wouldn't do that.
I would use:

<xsl:variable name="Minimum">
<xsl:call-template name="FindMin"/>
</xsl:variable>

<xsl:call-template name="do-something">
<xsl:with-param name="parameter" select="$Minimum"/>
</xsl:call-template>

Or, if the minimum's only purpose is being fed to another template ,I'd prefer to use:

<xsl:call-template name="do-something">
<xsl:with-param name="parameter">
<xsl:call-template name="FindMin"/>
</xsl:with-param>
Second, could you step through the
code for me so I understand how the execution flows through. I'm using
the XSLT engine provided by Altova and that doesn't exactly provide a
friendly debug environment. :p

<xsl:template name="FindMin">
<!-- if the param 'Min' is empty, give it some 'value' attribute (It doesn't matter from which node it comes) -->
<xsl:param name="Min"><xsl:value-of select="//@value"/></xsl:param>
<xsl:choose>
<xsl:when test="count(//*[@value &lt; $Min]) &gt; 0">
<!-- if the current node has any descendants with a 'value' attribute smaller than the current minimum -->
<!-- call this template again with a 'Min' parameter that is equal to the first 'value' attribute smaller than the current Minimum -->
<xsl:call-template name="FindMin">
<!-- the current node remains the same: we don't plunge into the tree -->
<xsl:with-param name="Min" select="//*[@value &lt; $Min]/@value"/>
</xsl:call-template>
</xsl:when>
<xsl:eek:therwise>
<!-- if the tree has no such descendents (i.e. the Minimum is found), display the Minimum -->
<!-- the template has done it's job and all recursively called templates above will close silently-->
<xsl:value-of select="$Min"/>
</xsl:eek:therwise>
</xsl:choose>
</xsl:template>

Btw, I don't have any debug environment.

Hope this helps.


regards,
 
J

Johnny Ooi

Wow, so I didn't need to worry about doing all those recursive calls, I
could have used the "//" selector instead. So this selects all
decendents at all levels, is that right?
 
J

Joris Gillis

Wow, so I didn't need to worry about doing all those recursive calls, I
could have used the "//" selector instead. So this selects all
decendents at all levels, is that right?

That's coorect. ('//' is short for '/descendant-or-self::node()/')

But one could argue if this Xpath approach is better than using recursive calls.

regards,
 
J

Johnny Ooi

Thanks for that, I'm going to go play with that and see what I can make
of it.

Johnny
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,997
Messages
2,570,241
Members
46,833
Latest member
BettyeMacf

Latest Threads

Top