Re: [xsl] Streaming terminology: Climbing

Subject: Re: [xsl] Streaming terminology: Climbing
From: "Abel Braaksma (Exselt)" <abel@xxxxxxxxxx>
Date: Sat, 25 Jan 2014 17:28:18 +0100
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