This is an archived snapshot of W3C's public bugzilla bug tracker, decommissioned in April 2019. Please see the home page for more details.

Bug 8253 - [XSLT 2.1] Allow xsl:variable before xsl:param
Summary: [XSLT 2.1] Allow xsl:variable before xsl:param
Status: CLOSED WONTFIX
Alias: None
Product: XPath / XQuery / XSLT
Classification: Unclassified
Component: XSLT 3.0 (show other bugs)
Version: Working drafts
Hardware: All All
: P2 enhancement
Target Milestone: ---
Assignee: Michael Kay
QA Contact: Mailing list for public feedback on specs from XSL and XML Query WGs
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2009-11-10 01:52 UTC by Greg Beauchesne
Modified: 2014-05-15 14:00 UTC (History)
1 user (show)

See Also:


Attachments

Description Greg Beauchesne 2009-11-10 01:52:12 UTC
Hello. I've been using XSLT for a while and I recently ran into a small
issue. Specifically, the recommendation forbids intermixing of
xsl:variable and xsl:param, which would be useful for default parameter 
values. This seems to me to be unnecessarily restrictive.

The XSLT 2.0 recommendation defines xsl:template as follows:

<xsl:template
    match? = pattern
    name? = qname
    priority? = number
    mode? = tokens
    as? = sequence-type>
    <!-- Content: (xsl:param*, sequence-constructor) -->
</xsl:template>

<xsl:param> elements can be assigned default values using the "select"
attribute or child content, and the default value can be defined in 
terms of the value of other parameters. This is useful, as it allows for 
dynamic defaults. However, there have been times where I would like to 
reuse a complex XPath expression in the default values of several 
parameters. For example, I would like to be able to rewrite this:

<xsl:template name="blah">
      <xsl:param name="param0"/>
      <xsl:param name="param1" select="$param0/a/long[@expr][1]" />
      <xsl:param name="param2" select="$param0/a/long[@expr][2]" />
</xsl:template>

as this:

<xsl:template name="blah">
      <xsl:param name="param0" />
      <xsl:variable name="tempVar" select="$param0/a/long[@expr]" />
      <xsl:param name="param1" select="$tempVar[1]" />
      <xsl:param name="param2" select="$tempVar[2]" />
</xsl:template>

Because the content of xsl:template is:

(xsl:param*, sequence-constructor)

...I am not allowed to put an xsl:variable before an xsl:param. Is there
any reason why this should be the case?

As a simple workaround, I can just change the <xsl:variable> to
<xsl:param> and it works exactly as expected, except that now $tempVar
is exposed as a template parameter when it was really supposed to be for
internal template use only.

Is there any chance that this could be relaxed in the next version of
XSLT and the xsl:template content changed to:

((xsl:variable | xsl:param)*, sequence-constructor)

...? Likewise for xsl:function if it is ever decided to allow for 
default parameter values there.
Comment 1 Mukul Gandhi 2009-11-10 03:24:25 UTC
(In reply to comment #0)

Personally speaking, I think something like this is not needed in an xs:template definition.

According to me, xsl:template is something like a subroutine or a method as in other programming languages. Ofcourse, a subroutine in languages like OO languages are a bit different than xsl:template's in XSLT, from execution point of view.

The most prevalent syntax of subroutines (here, xsl:template is similar to a subroutine) is the subroutine name, subroutine parameters and return type.

I don't think, an existence of variable between xsl:template parameters is a good design choice.

A workaround like, another parameter should be ok, but certainly a variable between xsl:param's doesn't look good to me. 

Regards,
Mukul
Comment 2 Michael Kay 2009-11-10 09:26:06 UTC
Reclassifying this as input to XSLT 2.1.

I don't have strong views on it either way.

There's been a related request to allow xsl:variable to appear before xsl:sort.
Comment 3 Mukul Gandhi 2009-11-10 09:45:04 UTC
(In reply to comment #2)
> Reclassifying this as input to XSLT 2.1.
> 
> I don't have strong views on it either way.
> 
> There's been a related request to allow xsl:variable to appear before xsl:sort.

To be able to specify xsl:variable before xsl:sort is quite useful, and can solve quite a number of new use cases.

But specifying xsl:variable between xsl:param's doesn't look good to me. To my thinking, that would violate the widely accepted norms of subroutine structure.

Regards,
Mukul

Comment 4 Greg Beauchesne 2009-11-10 11:35:53 UTC
(In reply to comment #3)
> (In reply to comment #2)
> > Reclassifying this as input to XSLT 2.1.
> > 
> > I don't have strong views on it either way.
> > 
> > There's been a related request to allow xsl:variable to appear before xsl:sort.

Yes, I saw that request and figured this one was along similar lines.

> To be able to specify xsl:variable before xsl:sort is quite useful, and can
> solve quite a number of new use cases.
> 
> But specifying xsl:variable between xsl:param's doesn't look good to me. To my
> thinking, that would violate the widely accepted norms of subroutine structure.

Well, there are a few things, though.

1. The ability to specify xsl:variable before xsl:sort doesn't add any functional capability to the language that it didn't already have (and thus doesn't allow you to solve anything you couldn't already solve). But it, like this, allows you to follow that common rule of programming: "don't repeat yourself." XSLT, being a functional language, doesn't suffer any side effects from throwing in variables there, which makes them a nice tool for reuse in both places.

2. As demonstrated, this is already possible with xsl:param. If you want to argue from a design standpoint, it would seem to me that it's better design to reflect the intent of the programmer when possible, rather than resorting to workarounds with potentially unintended consequences. In this case, the intent is "here's a sub-expression I want to reuse" as opposed to "here's a parameter I want to allow callers to override".

3. Parameter defaults can already get pretty complicated when using the element content instead of @select, and that includes putting xsl:variable inside. (although of course that has no scope outside of the parameter default) Granted, a good editor with XML element-folding capabilities will hide this part from you, but when looking at the full XML, there's visually not much difference between this:

<xsl:param name="param1">
    <xsl:variable name="x" select="..." />
    <xsl:variable name="y" select="..." />
    ...
</xsl:param>
<xsl:param name="param2" select="..." />

...and this:

<xsl:param name="param1" select="..." />
<xsl:variable name="x" select="..." />
<xsl:variable name="y" select="..." />
<xsl:param name="param2" select="..." />

-----

Overall, were it not for the existence of default parameter values, I would agree with you; hence why I said in the initial request "Likewise for xsl:function if it is ever decided to allow for default parameter values there." -- there's no need without the defaults. But we have them, they are incredibly useful (especially when defining defaults in terms of other parameters), and I think this would be something that would not hurt the language.
Comment 5 Michael Kay 2009-11-10 12:23:20 UTC
>I think this would be something that would not hurt the language.

My initial feeling is that there's nothing intrinsically wrong with the idea - it wouldn't hurt - but I'm not sure it would benefit enough people to be worth doing. Obviously, the WG will look at it and make a decision.
Comment 6 Mukul Gandhi 2009-11-10 12:52:36 UTC
(In reply to comment #5)
> >I think this would be something that would not hurt the language.
> 
> My initial feeling is that there's nothing intrinsically wrong with the idea -
> it wouldn't hurt - but I'm not sure it would benefit enough people to be worth
> doing. Obviously, the WG will look at it and make a decision.

In the first post, it was suggested that a capability like following is needed:

<xsl:template name="blah">
  <xsl:param name="param0" />
  <xsl:variable name="tempVar" select="$param0/a/long[@expr]" />
  <xsl:param name="param1" select="$tempVar[1]" />
  <xsl:param name="param2" select="$tempVar[2]" />
</xsl:template>

But as per the XSLT 2.0 spec, the contents of xsl:template can be as follows:

(xsl:param*, sequence-constructor)

I don't think, a change like as suggested should be added to the langauge, as it corrupts the basic design of a subroutine. For this particular thread, I am referring to xsl:template as a subroutine.

Subroutine structures are fairly standard, and XSLT seems to be no different in this regard. The basic essence of certain structures need to be preserved (here, that's a subroutine :( ).

As suggested by the user, an easy workaround is possible for this particular need. I don't think a facility should be added to the language, unless there is strong demand from a large group of users.

I think, a facility like this can be added as an extension to XSLT processors. But I don't think, it should be added to the main language :(

But if the XSL WG chooses to add this facility to the main XSLT language, users cannot do much about it :)

Regards,
Mukul

Comment 7 Greg Beauchesne 2009-11-10 17:29:03 UTC
(In reply to comment #5)
> doing. Obviously, the WG will look at it and make a decision.

Understood. That's all I can ask. Thanks for your consideration.
Comment 8 Michael Kay 2010-07-16 12:43:17 UTC
The Working Group decided not to adopt this idea, although it is interesting and has some attractions. One argument is that the use case isn't strong enough; another is that there are disadvantages in terms of making the interface to the template less visible, and in terms of implementation impacts. But thanks for the comment.