Re: [xsl] Streaming terminology: Climbing

Subject: Re: [xsl] Streaming terminology: Climbing
From: Michael Kay <mike@xxxxxxxxxxxx>
Date: Wed, 29 Jan 2014 11:50:25 +0000
Yes, it's a very useful explanation.

I think your conceptual model that the processor is "positioned just after the
start tag" is probably helpful to many people but it's worth pointing out that
it's not in the spec and we try not to over-constrain implementations. There's
also a glitch in it in that we (deliberately) define has-children() to be an
inspection construct, and to evaluate this function the processor needs to
peek just beyond the end of the start tag. (Saxon doesn't yet implement
this).

There's also a minor error where you say:

A construct is climbing if, when executed, it yields the context node (self)
or ancestors of the context node.

Apart from the fact that attribute selection is also climbing (despite the
name), this confuses the role of the context node and the current streaming
position. For example the construct

descendant::x/parent::y

is climbing, although it does not select ancestors of the context node. It's
climbing because it reads information from the "stack" of ancestor data that
is maintained as the streaming processor works its way through the document,
and when you're positioned in that stack, your ability to select downwards is
constrained.

Incidentally, at one time we defined the spec so that as well as retaining
"the start tags of all ancestors" in this stack, we also retained some
positional information about the position of each ancestor relative to its
siblings, allowing match patterns such as match="para[1]". This has been
dropped from the spec, but it's partially implemented in Saxon, and I have yet
to decide whether to retain it in some form.

Michael Kay
Saxonica

On 29 Jan 2014, at 10:38, Costello, Roger L. <costello@xxxxxxxxx> wrote:

> Hi Folks,
>
> Thanks to Abel's outstanding explanation, I created a few Powerpoint slides
to explain "climbing":
>
> http://www.xfront.com/XSLT-Streaming-Terminology-Climbing.pptx
>
> Would you take a look at the slides and let me know of any inaccuracies
please?
>
> /Roger
>
> -----Original Message-----
> From: Abel Braaksma (Exselt) [mailto:abel@xxxxxxxxxx]
> Sent: Saturday, January 25, 2014 11:28 AM
> To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> Subject: Re: [xsl] Streaming terminology: Climbing
>
> Hi Roger,
>
> See comments between the lines.
>
> Cheers,
> Abel
>
>
> On 24-1-2014 11:15, Costello, Roger L. wrote:
>> What nodes can a construct return in order for it to be considered a
climbing construct?
>>
>> This XPath expression
>>
>> 	@*
>>
>> returns all the attributes of the context node, so  @*  is a climbing
construct, correct?
>
> Yes, this is a climbing construct, even though it may feel as if you are
> striding (moving sideways on the Title-element). Visited nodes,
> including current namespace nodes and attributes are remembered by the
> processor, but only for the ancestor-or-self axis. Once the Title
> element is visited, the streaming processor has already processed all
> its attributes and the read pointer is considered to be at the end of
> the opening tag Title, hence the term "climbing".
>
>> This XPath expression
>>
>> 	ancestor::*
>>
>> returns all the ancestors of the context node, so  ancestor::*  is a
climbing construct, correct?
>
> Yes, it is a climbing construct. However, unless you select other
> climbing nodes from here and unless you atomize the results (without
> consuming the contents of the children) you can't do much with it.
>
>> This XPath expression
>>
>> 	for $i in ancestor::node() return $i
>>
>> also returns all the ancestors of the context node, so  for $i in
ancestor::node() return $i  is a climbing construct, correct?
>
> No, this is not a climbing construct, it is roaming and free-ranging.
> The part in the middle, the expression ancestor::node() is climbing, but
> you are not allowed to return the nodes from a for-in-return expression.
> The return expression must be grounded for the whole construct to be
> streamable. An example with a climbing construct in a for-expression
> that is also streamable is:
>
> for $i in ancestor::node() return string(@id)
> for $i in somechild return $i/name()
>
>
>> This XPath expression
>>
>> 	../@*
>>
>> returns all the attributes of the parent of the context node, so  ../@*  is
a climbing construct, correct?
>
> Yes, that is correct. But, just as in the previous example, be aware
> that you cannot return this, because then navigating away from the node
> would be possible at a later stage. Hence, you should typically use
> expressions like this this in expressions that have operator usage
> absorption or inspection, but not navigation.
>
>> This XPath expression
>>
>> 	./namespace::*
>>
>> returns all the namespaces visible on the context node, so  ./namespace::*
is a climbing construct, correct?
>
> Correct.
>
>> Notice that all the examples are XPath expressions. Can you give an example
or two of a climbing construct that is not an XPath expression?
>
> Since every expression is an XPath expression, except for patterns (but
> they inherit the syntax), the only other thing that can potentially be
> climbing is a construct. Looking over the rules, it turns out that, if I
> interpret them correctly, only a choice operand group can potentially be
> climbing. There are two constructs that form a choice operand group. One
> is an if-then-else expression (which is an XPath, so I don't consider it
> an answer to your question), the other are the sequence constructors in
> an xsl:choose construct. This turns out to be climbing, but only when
> the tests are grounded and motionless. A simple example:
>
> <xsl:choose>
>    <xsl:when test="local-name(.) eq 'foo'">
>       <xsl:sequence select="parent::bar" />
>   </xsl:when>
>   <xsl:otherwise>
>      <xsl:sequence select="parent::foo" />
>   </xsl:otherwise>
> </xsl:choose>
>
> In the above construct, the posture of each operand in the group is
> climbing (as a result of the operand usage being transmission and the
> use of the parent axis). The combined posture of the choice operand
> group, however, is crawling. Also, since you are not allowed to return
> streaming nodes, the xsl:sequence constructor should either be removed,
> or the result should be wrapped in an xsl:value-of or something similar.
>
> Other than that, I don't believe there is a construct that is climbing
> and that doesn't visit nodes using any of the axis mentioned in the
> climbing-description.
>
>>
>> To recap:
>>
>> 	A construct is climbing if, when executed, it yields
>> 	the context node (self) or ancestors of the context node.
>> 	Also a climbing construct can return attributes of
>> 	the context node or attributes of ancestor nodes.
>> 	Finally, a climbing construct can return namespaces
>> 	that are visible on the context node or on any ancestor.
>>
>> Is that correct?
>
> Yes, it could. However, as you write here, because it "can return
> nodes", and because streaming nodes cannot be moved around (because it
> cannot statically be assessed what happens to them in a later
> construct), this is not permitted in constructs such as xsl:with-param,
> xsl:variable, xsl:apply-templates or as function arguments to stylesheet
> functions (unless atomized).
>
>> Is there anything else important to know about understanding what a
climbing construct is?
>
> Probably a lot, but I think you got the essence wrapped up here.
> Climbing constructs play an important role in path expressions and it is
> important to understand that something like x/ancestor::y/z is not
> allowed, because you are allowed to climb, but not allowed to descend
> afterwards.

Current Thread