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 27051 - [XSLT30] Resolution to bug 25185 introduced a bug in streaming rules of xsl:apply-templates
Summary: [XSLT30] Resolution to bug 25185 introduced a bug in streaming rules of xsl:a...
Status: CLOSED FIXED
Alias: None
Product: XPath / XQuery / XSLT
Classification: Unclassified
Component: XSLT 3.0 (show other bugs)
Version: Last Call drafts
Hardware: PC Windows NT
: P2 normal
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: 2014-10-14 22:25 UTC by Abel Braaksma
Modified: 2015-10-29 09:50 UTC (History)
0 users

See Also:


Attachments

Description Abel Braaksma 2014-10-14 22:25:18 UTC
The resolution for bug 25185 was to allow crawling expressions in atomizing constructs, but to make an exception for instructions such as xsl:apply-templates and xsl:for-each. One of the changes was made in 19.8.4.5:

<quote>
4. If the select expression is climbing or crawling, then roaming and free-ranging
</quote>

But in the past we allowed things like <xsl:apply-templates select="attribute::*" /> and in fact, it is still visible in an example (see 6.7.3 Built-in Templates: Shallow Copy).

I think the idea was that childless nodes are allowed in apply-templates, even with climbing expressions, because a downward expression does no harm on them. 

This rule is already in the general streamability rules section (1.b.iii.A.I), so the fix for this issue could be as simple as remove "climbing" from the above phrase (item #5 in the list uses the general streamability rules, which covers the rest).
Comment 1 Michael Kay 2014-10-24 16:30:28 UTC
I'm a little surprised to hear that the spec at one time allowed this.

While it's clear that it can be made to work, I'm a bit worried about whether it's well grounded in the theory. My basic concerns are that when we evaluate a template rule for streamability, we assume the context posture is striding. But in this case the select expression that selected the nodes is climbing. If we work through all the combinations of what you can do with the nodes, it seems that all the permitted actions make sense, but it still doesn't feel right to make this switch from climbing to striding as we enter the called template.

And is this the only place where this occurs? What about other places where we require (and assume) striding expressions, such as for-each and for-each-group and iterate? Is it safe to use attribute::* in all these contexts, on the same basis?

If so, perhaps we should change the table in 9.8.7.7 so that selecting attributes or namespaces from a striding origin gives a striding result? (And perhaps selecting them from a crawling origin also gives a striding result?)

We could then also consider improving the rules for union expressions so that *|@* is striding: the rule would perhaps be that if both operands are striding if at most one operand can select elements, then the result is striding.
Comment 2 Michael Kay 2014-10-24 16:38:32 UTC
This is starting to feel similar to the proposal to make more expressions striding in

https://lists.w3.org/Archives/Member/w3c-xsl-wg/2014Oct/0021.html

I'm wondering if even selecting attributes from a climbing posture can be made striding? The same arguments apply: going upwards gets you back to climbing which stops you coming back down, and going downwards gives you nothing so it's safe.
Comment 3 Michael Kay 2014-10-25 11:44:21 UTC
I have managed to convince myself that we can change the table in 19.8.7.7 (Streamability of axis steps) to say:

Climbing | attribute, namespace | Striding | Motionless
Striding | attribute, namespace | Striding | Motionless
Crawling | attribute, namespace | Striding | Motionless

In addition, I think we can incorporate the changes proposed in 

https://lists.w3.org/Archives/Member/w3c-xsl-wg/2014Oct/0033.html

I propose to do this by adding a new column to the table "selects elements", defined as meaning that the static type of the axis expression contains U{element}. The two rows in the table that currently produce a crawling result will then be subdivided so that if selects elements is "no", the result posture is striding instead of crawling.

I don't think we need to add an extra row for

Crawling | child, descendant, d-or-self | elements="no" | Striding | Consuming

Because this is handled under the rules for scanning expressions. But we should change rule 2(b) for scanning expressions (in 19.8.7.6) from

If the expression is a scanning expression then its posture is crawling.

to

If the expression is a scanning expression then 

* if the static type of the expression contains U{element} then its posture is crawling.

* otherwise, its posture is striding.
Comment 4 Abel Braaksma 2014-10-26 14:57:46 UTC
> I'm a little surprised to hear that the spec at one time allowed this.

For reference, it is here: http://www.w3.org/TR/2013/WD-xslt-30-20131212/#dt-general-streamability-rules. The last step applies the general streamability rules with absorption for @select, and in the GSR we say that absorption with childless node kinds turns absorption into inspection.

The rule for changing absorption into inspection applied to all of striding, climbing and crawling postures (though text() or processing-instruction() clearly can never be climbing).

This rule worked find in practice, because namespace and attribute axes have always been motionless and you cannot select children from them.

> What about other places where we require (and assume) striding expressions,
> such as for-each and for-each-group and iterate? Is it safe to use 
> attribute::* in all these contexts, on the same basis?

This worked because of the GSR. Selecting a climbing axis with attribute nodes on a for-each would result in a climbing context posture for the body of the for-each, but in any absorption usage, the GSR kicks in and allows this because the nodes are childless (GSR rule 1.b.iii).

So yes, while perhaps not ideal in terminology, it worked well. 

This bug report was deliberately specifically about xsl:apply-templates, because the changes in the spec did not break existing rules for xsl:for-each(-group), afaict, only for xsl:apply-templates.

> but it still doesn't feel right to make this switch from climbing to 
> striding as we enter the called template.
> I'm wondering if even selecting attributes from a climbing posture 
> can be made striding?

I believe that in XPath they are considered downward axes, and in light of that, it has always been kind of odd to consider the attribute and namespace axes climbing, but we had good reasons for it (it worked well with other existing climbing axes like ancestor).

If we turn them into striding and motionless I think it simplifies many situations, but also becomes a cameleon: it will be the only axis that can change climbing into striding (but we have something similar to crawling with text nodes, which changes crawling into striding).

Recognizing this situation and allowing more axis paths to be able to return striding postures results in more expressions to be streamable without adding complexity. I think that is a good thing.
Comment 5 Michael Kay 2014-12-18 21:22:18 UTC
The WG agreed to make changes as described in message 

https://lists.w3.org/Archives/Member/w3c-xsl-wg/2014Dec/0021.html
(member-only link)

The most important change proposed is that axis expressions using the attribute axis should now have striding rather than climbing posture. This makes it possible to use such expressions in calls on xsl:apply-templates in a streaming mode.