XSLT: Is the variable scope of <xsl:if> local?

H

Hoi Wong

With the XSLT 1.0 engine that I was forced to use, I have to parse old XML
scripts where the number (to be parsed and saved into $EPISODE_NUMBER_RAW)
that I want to parse is written with a comma seperator if it goes beyond 3
digits. i.e. the variable might be parsed as a string '1,324' or a number
56, depending on which XML file I have.

I was trying to get rid of the comma seperator by breaking the string into
two parts (that number will never go beyond 5 digits), like this:


<xsl:choose>
<xsl:when test="contains($EPISODE_NUMBER_RAW, ',')">
<xsl:variable name="EPISODE_NUMBER"
select="concat(substring-before($EPISODE_NUMBER_RAW,','),
substring-after($EPISODE_NUMBER_RAW, ',') )"/>
</xsl:when>

<xsl:eek:therwise>
<xsl:variable name="EPISODE_NUMBER" select="$EPISODE_NUMBER_RAW"/>
</xsl:eek:therwise>

</xsl:choose>

<xsl:value-of select="$EPISODE_NUMBER"/>


However, the XSLT throws an error saying that $EPISODE_NUMBER is not found.
Does <xsl:choose> has its own variable scope? If so, can anybody give me a
pointer on how to solve the problem?

Thanks a lot in advance.

Cheers,
Hoi
 
P

Pavel Lepin

Hoi Wong said:
With the XSLT 1.0 engine that I was forced to use, I have
to parse old XML scripts where the number (to be parsed
and saved into $EPISODE_NUMBER_RAW) that I want to parse
is written with a comma seperator if it goes beyond 3
digits. i.e. the variable might be parsed as a string
'1,324' or a number 56, depending on which XML file I
have.

I was trying to get rid of the comma seperator by breaking
the string into two parts (that number will never go
beyond 5 digits), like this:

640K of memory will be enough for anybody.
<xsl:choose>
<xsl:when test="contains($EPISODE_NUMBER_RAW, ',')">
<xsl:variable name="EPISODE_NUMBER"
select="concat(substring-before($EPISODE_NUMBER_RAW,','),
substring-after($EPISODE_NUMBER_RAW, ',') )"/>
</xsl:when>
<xsl:eek:therwise>
<xsl:variable name="EPISODE_NUMBER"
select="$EPISODE_NUMBER_RAW"/>
</xsl:eek:therwise>
</xsl:choose>

However, the XSLT throws an error saying that
$EPISODE_NUMBER is not found. Does <xsl:choose> has its
own variable scope? If so, can anybody give me a pointer
on how to solve the problem?

Works:

<xsl:variable name="number">
<xsl:choose>
<xsl:when test="contains($raw-number,',')">
<xsl:value-of select=
"
concat(substring-before($raw-number,','),
substring-after($raw-number,','))
"/>
</xsl:when>
<xsl:eek:therwise>
<xsl:value-of select="$raw-number"/>
</xsl:eek:therwise>
</xsl:choose>
</xsl:variable>

Better:

<xsl:variable name="number"
select="translate($raw-number,',','')"/>

Even better - stuff it into a named template and invoke
that. You never know when you might need this again.
 
H

Hoi Wong

translate() works perfectly! Thanks.



Pavel Lepin said:
640K of memory will be enough for anybody.


Works:

<xsl:variable name="number">
<xsl:choose>
<xsl:when test="contains($raw-number,',')">
<xsl:value-of select=
"
concat(substring-before($raw-number,','),
substring-after($raw-number,','))
"/>
</xsl:when>
<xsl:eek:therwise>
<xsl:value-of select="$raw-number"/>
</xsl:eek:therwise>
</xsl:choose>
</xsl:variable>

Better:

<xsl:variable name="number"
select="translate($raw-number,',','')"/>

Even better - stuff it into a named template and invoke
that. You never know when you might need this again.
 
P

Pavel Lepin

Joseph Kesselman said:
_All_ XSLT variable scopes are local.

Ah, but what about xsl:variable children of xsl:stylesheet
element? Besides, I think it's not about lexical/dynamic
scoping, but about what a variable's scope is. This is
rarely if ever mentioned in tutorials, so you've got to
shuffle through the spec to get a precise definition, and
we all know how averse your J. Random Developer is to that.

Yes, the scope of a local variable is limited by the nearest
enclosing block in many of the modern languages. But XSLT
doesn't really have blocks; and, say, PHP does not adhere
to that convention. Compare:

pavel@debian:~/dev/php$ a scope.pl
use warnings; use strict;
sub tst {
my $foo = 1;
if ($foo) {
my $bar = 2;
}
print($foo . ' ' . $bar . "\n");
}
tst();
pavel@debian:~/dev/php$ perl scope.pl
Global symbol "$bar" requires explicit package name at
scope.pl line 7.
Execution of scope.pl aborted due to compilation errors.
pavel@debian:~/dev/php$ a scope.php
<?php error_reporting(E_ALL | E_STRICT);
function tst() {
$foo = 1;
if ($foo) {
$bar = 2;
}
print($foo . ' ' . $bar . "\n");
}
tst(); ?>
pavel@debian:~/dev/php$ php scope.php
1 2
pavel@debian:~/dev/php$

(Perl also has dynamic scoping, using which would produce
the same behaviour as observed in the PHP script above -
but the point is that in PHP, the scope of $bar is limited
by the body of the function it's defined in, not by the
nearest enclosing block.)

I've also had some trouble with this in my first days with
XSLT, so I can sort of sympathise with the OP.
 
J

Joseph Kesselman

Pavel said:
Ah, but what about xsl:variable children of xsl:stylesheet
element?

They're local to the stylesheet element and its content.
scoping, but about what a variable's scope is.

A variable's lexical scope in XSLT -- the area within which that
variable can be referenced by name -- is the xsl:variable element's
following siblings and their descendants, unless the same name is used
for another variable within that scope. Its dynamic scope is the
execution of the element which encloses the xsl:variable element.

Putting it another way: An XSLT variable is created at the xsl:variable
element, is directly visible only within the element that element
appears within.
 
P

Pavel Lepin

Joseph Kesselman said:
They're local to the stylesheet element and its content.

The spec seems to disagree [11.4]:

A top-level variable-binding element declares a global
variable that is visible everywhere.

I believe this affects also affects imports and includes,
but gotta test that on a real processor or shuffle through
the spec some more to see if there's an explicit
description of those cases.
 
J

Joseph Kesselman

I believe this affects also affects imports and includes,

.... I think that's right. One can quibble about the details of how this
interacts with import/include -- whether those "become part of the same
stylesheet element" in some reasonable sense -- but I don't think it's
worth debating.

In practical terms, it's a difference that rarely, if ever, makes a
difference.
 
P

P. Lepin

Joseph said:
... I think that's right. One can quibble about the details of how this
interacts with import/include -- whether those "become part of the same
stylesheet element" in some reasonable sense -- but I don't think it's
worth debating.

In practical terms, it's a difference that rarely, if ever, makes a
difference.

I apologise for displaying the symptoms of my Compulsive Nitpicking Syndrome
in public yet again. :)
 

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,731
Messages
2,569,432
Members
44,832
Latest member
GlennSmall

Latest Threads

Top