This section contains rules that can be used to determine properties of constructs in the stylesheet — specifically, the posture and sweep of a construct — which enable the streamability of the stylesheet to be assessed.
These properties are used to determine the streamability of:
The xsl:source-document
instruction: see 18.1 The xsl:source-document Instruction
Stylesheet functions: see 19.8.5 Classifying Stylesheet Functions
The xsl:merge
instruction: see 15.4 Streamable Merging
In each case, the conditions for constructs to be guaranteed-streamable are defined in terms of these properties. The result of this analysis in turn (see 19.10 Streamability Guarantees) imposes rules on how the constructs are handled by processors that implement the streaming feature. The analysis has no effect on the behavior of processors that do not implement this feature.
The analysis is relevant to constructs such as streamable template rules and the
xsl:source-document
instruction that process a single streamed input
document. The xsl:merge
instruction, which processes multiple streamed
inputs, has its own rules.
The rules in this section operate on the expression tree (more properly, construct tree) that is typically output by the XSLT and XPath parser. For the most part, the rules depend only on identifying the syntactic constructs that are present.
The rules in this section generally consider each component in the stylesheet (and in the case of template rules, each template rule) in isolation. The exception is that where a component contains references to other components (such as global variables, functions, or named templates), then information from the signature of the referenced component is sometimes used. This is invariably information that cannot be changed if a component is overridden in a different package. The analysis thus requires as a pre-condition that function calls and calls on named templates have been resolved to the extent that the corresponding function/template signature is known.
The detailed way in which the construct tree is derived from the lexical form of the stylesheet is not described in this specification. There are many ways in which the tree can be optimized without affecting the result of the rules in this section: for example, a sequence constructor containing a single instruction can be replaced by that instruction, and a parenthesized expression can be replaced by its content.
[Definition: The term construct refers to the union of the following: a sequence constructor, an instruction, an attribute set, a value template, an expression, or a pattern.]
These constructs are classified into
construct kinds: in particular, instructions are classified according to the name of the XSLT instruction,
and expressions are classified according to the
most specific production in the XPath grammar that the expression satisfies. (This
means, for example, that 2+2
is classified as an AdditiveExpr
,
rather than say as a UnionExpr
; although it also satisfies the production
rule for UnionExpr
, AdditiveExpr
is more specific.)
[Definition: For every construct kind, there is a
set of zero or more operand roles.] For example, an
AdditiveExpr
has two operand roles, referred to as the left-hand operand
and the right-hand operand, while an IfExpr
has three, referred to as the
condition, the then-clause, and the else-clause. A function call with three arguments
has three operand roles, called the first, second, and third arguments. The names
of the
operand roles for each construct kind are not formally listed, but should be clear
from
the context.
[Definition: In an actual instance of a construct, there will
be a number of operands. Each operand is itself a construct; the construct tree can be defined as the transitive relation
between constructs and their operands.] Each operand is associated with exactly one of
the operand roles for the construct type. There may be operand roles where the operand
is optional (for example, the separator
attribute of the
xsl:value-of
instruction), and there may be operand roles that can
be occupied by multiple operands (for example, the xsl:when/@test
condition
in xsl:choose
, or the arguments of the concat
FO30
function).
Operand roles have a number of properties used in the analysis:
The required type of the operand. This is explicit in the case of function calls (the required type is defined in the function signature of the corresponding function). In other cases it is implicit in the detailed rules for the construct in question. In practice streamability analysis makes only modest use of the required type; the main case where it is relevant is for a function or template call, where knowing that the required type is atomic enables the inference that the operand usage for a supplied node is absorption.
[Definition: The operand usage. This gives information, in the case where the operand value contains nodes, about how those nodes are used. The operand usage takes one of the values absorption, inspection, transmission, or navigation. ]The meanings of these terms are explained in 19.3 Operand Roles. If the required type of the operand does not permit nodes to be supplied (for example because the required type is a function item or a map), then the operand usage is inspection, because the only run-time operation on a supplied node will be to inspect it, discover it is a node, and raise a type error.
In the particular case where the required type is atomic, and any supplied nodes are atomized, the operand usage will be absorption, because atomize is a special case of absorption.
[Definition: Whether or not the operand is higher-order. For this purpose an operand O of a construct C is higher-order if the semantics of C potentially require O to be evaluated more than once during a single evaluation of C.] More specifically, O is a higher-order operand of C if any of the following conditions is true:
The context item for evaluation of O is different from the context item for evaluation of C.
C is an instruction and O is a
pattern (as with the from
and
count
attributes of xsl:number
, and the
group-starting-with
and group-ending-with
attributes of xsl:for-each-group
).
C is an XPath for
, some
, or
every
expression and O is the expression in its
return
or satisfies
clause.
C is an inline function declaration and O is the expression in its body.
Note:
There is one known case where this definition makes
an operand higher-order even though it is only evaluated once: specifically, the sequence
constructor contained in the body of an xsl:copy
instruction that has a
select
attribute. See 19.8.4.12 Streamability of xsl:copy for further details.
[Definition: For some construct
kinds, one or more operand roles may be defined to form a choice operand
group. This concept is used where it is known that operands are mutually exclusive (for example the
then
and else
clauses in a conditional
expression).]
[Definition: The combined posture of a choice operand group is determined by the postures of the operands in the group (the operand postures), and is the first of the following that applies:
If any of the operand postures is roaming, then the combined posture is roaming.
If all of the operand postures are grounded, then the combined posture is grounded.
If one or more of the operand postures is climbing and the remainder (if any) are grounded, then the combined posture is climbing.
If one or more of the operand postures is striding and the remainder (if any) are grounded, then the combined posture is striding.
If one or more of the operand postures is crawling and each of the remainder (if any) is either striding or grounded, then the combined posture is crawling.
Otherwise (for example, if the group includes both an operand with climbing posture and one with crawling posture), the combined posture is roaming.
]
[Definition: The
type-determined usage of an operand is as
follows: if the required type (ignoring occurrence indicator) is
function(*)
or a subtype thereof, then inspection; if the required type (ignoring occurrence indicator) is an atomic or union type, then absorption; otherwise navigation.]
[Definition: The type-adjusted posture and sweep of a construct C, with respect to a type T, are the posture and sweep established by applying the general streamability rules to a construct D whose single operand is the construct C, where the operand usage of C in D is the type-determined usage based on the required type T.]
Note:
In effect, the type-adjusted posture and sweep are the posture and sweep of the
implicit expression formed to apply the function conversion rules
to the argument of a function or template call, or to the result of a function or
template, given knowledge of the required type. For example, an expression such as
discount
in the function call abs(discount)
, which would
otherwise be striding and consuming, becomes
grounded and consuming because of the
implicit atomization triggered by the function conversion rules.
The process of determining whether a construct is streamable reduces to determining properties of the constructs in the construct tree. The properties in question (which are described in greater detail in subsequent sections) are:
The static type of the construct. When the construct is evaluated, its value will always be an instance of this type. The value is a U-type; although type inferencing is capable of determining information about the cardinality as well as the item type, the streamability analysis makes no use of this.
The context item type: that is, the static type of the context item potentially used as input to the construct. When the construct is evaluated, the context item used to evaluate the construct (if it is used at all) will be an instance of this type.
[Definition: The posture of the expression. This captures information about the way in which the streamed input document is positioned on return from evaluating the construct. The posture takes one of the values climbing, striding, crawling, roaming, or grounded.] The meanings of these terms are explained in 19.4 Determining the Posture of a Construct.
[Definition: The context posture. This captures information about how the context item used as input to the construct is positioned relative to the streamed input. The context posture of a construct C is the posture of the expression whose value sets the focus for the evaluation of C.] Rules for determining the context posture of any construct are given in 19.5 Determining the Context Posture.
The sweep of the construct. The sweep of a construct gives information about whether and how the evaluation of the construct changes the current position in a streamed input document. The possible values are motionless, consuming, and free-ranging. These terms are explained in 19.6 The Sweep of a Construct.
The values of these properties for a top-level construct such as the body of a template rule determine whether the construct is streamable.
The values of these properties are not independent. For example, if the static type is atomic, then the posture will always be grounded; if the sweep is free-ranging, then the posture will always be roaming.
The posture and sweep of a
construct, as defined above, are calculated in relation to a
particular streamed input document. If there is more than one streamed input document,
then a construct that is motionless with respect to one streamed input might be
consuming with respect to another. In practice, though, the streamability analysis
is
only ever concerned with one particular streamed input at a time; constructs are
analyzed in relation to the innermost containing xsl:template
,
xsl:source-document
, xsl:accumulator
, or
xsl:merge-source
element, and this container implicitly defines the
streamed input document that is relevant. The streamed input document affecting a
construct is always the document that contains the context item for evaluation of
that
construct.
[Definition: The static type of a construct is such that all values produced by evaluating the construct will conform to that type. The static type of a construct is a U-type.]
[Definition: A U-type is a set of fundamental item types.]
[Definition: There are 28
fundamental item types: the 7 node kinds defined in [XDM 3.0] (element, attribute, etc.), the 19 primitive atomic
types defined in [XML Schema Part 2], plus the types
function(*)
and xs:untypedAtomic
. The fundamental
item types are disjoint, and every item is an instance of exactly one of
them.]
More specifically, the fundamental item types are:
document-node()
, element()
, attribute()
,
text()
, comment()
,
processing-instruction()
, namespace-node()
;
xs:boolean
, xs:double
, xs:decimal
,
xs:float
, xs:string
, xs:dateTime
,
xs:date
, xs:time
, xs:gYear
,
xs:gYearMonth
, xs:gMonth
,
xs:gMonthDay
, xs:gDay
, xs:anyURI
,
xs:QName
, xs:NOTATION
,
xs:base64Binary
, xs:hexBinary
,
xs:duration
function(*)
xs:untypedAtomic
A value V (in general, a sequence) is an instance of a U-type
U if every item in V is an instance of one of the fundamental item types in U.
For example, the sequence (23, "Paris")
is an instance of the U-type
U{xs:string, xs:decimal, xs:date}
because both items in the sequence
belong to item types in this U-type.
Note:
It is a consequence of this rule that the empty sequence, ()
, is an
instance of every U-type.
A U-type is represented in this specification using the notation
U{t1, t2, t3, ...} where t1, t2, t3, ...
are the names of
the fundamental item types making up the U-type. The item types are represented using
the syntax of the ItemTypeXP30
production in XPath, for example comment()
or xs:date
.
Note:
This means that the order of t1, t2, t3, ...
has no significance:
U{A, B} is the same U-type as U{B, A}.
The smallest U-type is denoted U{}. This is not an empty type; like every
other U-type, it has the empty sequence ()
as an instance. For
convenience, the universal U-type is represented as U{*}; the U-type
corresponding to the set of 7 node kinds is written U{N}, and the U-type
corresponding to all atomic values (that is, the 19 primitive atomic types plus
xs:untypedAtomic
) is written U{A}.
Because a U-type is a set, the operations of union, intersection, and difference are defined over U-types, and the result is always a U-type. If one U-type U is a subset of another U-type V, then U is said to be a subtype of V, and V is said to be a supertype of U.
In some cases the inference of a static type depends on the declared types of variables or functions. Since declared types use the SequenceType syntax, there is therefore a mapping defined from SequenceTypes to U-types. The mapping is as follows:
The SequenceType
empty-sequence()
maps to U{}
For every other SequenceType, the mapping depends only on the item type and ignores the occurrence indicator. The mapping from item types is as follows:
item()
maps to U{*}
AnyKindTest
(node()
) maps to
U{N}
DocumentTest
maps to U{document-node()}
ElementTest
and SchemaElementTest
map to
U{element()}
AttributeTest
and SchemaAttributeTest
map to
U{attribute()}
TextTest
maps to U{text()}
CommentTest
maps to U{comment()}
PITest
maps to U{processing-instruction()}
NamespaceNodeTest
maps to U{namespace-node()}
FunctionTest
, MapTest
,
and (if the XPath 3.1 Feature
is implemented) ArrayTest
map to U{function(*)}
The QName xs:error
maps to U{}
A QName Q representing an atomic type that is a fundamental item type maps to U{Q}
A QName Q representing an atomic type derived from a fundamental item type F maps to U{F}
A QName Q representing a pure union type maps to a U-type containing the fundamental item types present in the transitive membership of the union, or from which the transitive members of the union are derived.
Although all constructs have a static type, the streamability analysis only needs to know the static type of XPath expressions, so the rules here are largely confined to that case. For patterns, the static type is deemed to be U{xs:boolean}, reflecting the fact that a pattern is essentially a function that can be applied to items to deliver a true or false (matching or non-matching) result. For constructs other than expressions and patterns, the static type for the purpose of streamability analysis is taken as U{*}.
The rules given here are deliberately simple. Implementations may well be able to compute a more precise static type, but this will rarely be useful for streamability analysis. The item type for each kind of XPath expression is determined by the rules below. In the first column, numbers in square brackets are production numbers from the XPath 3.0 and XPath 3.1 specifications respectively. In the second column, the Proforma uses an informal notation used both to provide a reminder of the syntax of the construct in question, and to attach labels to its operand roles so that they can be referred to in the text of the third column.
Construct | Proforma | Static Type |
---|---|---|
Expr [6,6] | E,F |
the union of the static types of E and F |
ForExpr [8,8] | for $x in S return E |
the static type of E |
LetExpr [11,11] | let $x := S return E |
the static type of E |
QuantifiedExpr [14,14] | some|every $x in S satisfies C |
U{xs:boolean} |
IfExpr [15,15] | if (C) then T else E |
the union of the static types of T and E |
OrExpr [16,16] | E or F |
U{xs:boolean} |
AndExpr [17,17] | E and F |
U{xs:boolean} |
ComparisonExpr [18,18] | E = F, E eq F, E is F |
U{xs:boolean} |
StringConcatExpr [19,19] | E || F |
U{xs:string} |
RangeExpr [20,20] | E to F |
U{xs:decimal} |
AdditiveExpr [21,21] | E + F |
U{A}. But if the expression is a predicate (that is, if it appears between square brackets in a filter expression or axis step), then U{xs:decimal, xs:double, xs:float} |
MultiplicativeExpr [22,22] | E * F |
U{A}. But if the expression is a predicate (that is, if it appears between square brackets in a filter expression or axis step), then U{xs:decimal, xs:double, xs:float} |
UnionExpr [23,23] | E | F |
the union of the static types of E and F |
IntersectExceptExpr [24,24] | E intersect F |
the intersection of the static types of E and F |
E except F |
the static type of E | |
InstanceOfExpr [25,25] | E instance of T |
U{xs:boolean} |
TreatExpr [26,26] | E treat as T |
the U-type corresponding to the SequenceType T |
CastableExpr [27,27] | E castable as T |
U{xs:boolean} |
CastExpr [28,28] | E cast as T |
if T is an atomic or pure union type, the corresponding U-type. Otherwise, for example if T is a list type, U{A}. |
UnaryExpr [29,30] | -N |
U{xs:decimal, xs:double, xs:float} |
SimpleMapExpr [34,35] | E ! F |
the static type of F |
PathExpr [35,36] | / |
U{document-node()} |
/P |
the static type of P | |
//P |
the static type of P | |
RelativePathExpr [36,37] | P/Q, P//Q |
the static type of Q |
AxisStep [38,39] | E[P] |
the static type of E: see 19.1.1 Static Type of an Axis Step |
ForwardStep [39,40], ReverseStep [42,43] | Axis::NodeTest |
See 19.1.1 Static Type of an Axis Step |
PostfixExpr [48,49] | Filter Expression E[P] |
the static type of E |
Dynamic Function Call F(X, Y) |
U{*}, unless ancillary information is available about the function signature of F: see below. | |
Literal [53,57] | "pH" , 93.7 |
U{xs:string}, U{xs:decimal}, or U{xs:double}, depending on the form of the literal |
VarRef [55,59] | $V |
For a variable declared using xsl:variable or
xsl:param , and for parameters of inline function
expressions: the declared type of the variable, defaulting to
U{*}. For variables declared using for ,
let , some , and every expressions:
the static type of the expression to which the variable is bound.
|
ParenthesizedExpr [57,61] | (E) |
the type of E |
() |
U{} (a type whose only instance is the empty sequence) | |
ContextItemExpr [58,62] | . |
the context item type: see below |
FunctionCall [59,63] | F(X, Y) |
In general: the U-type corresponding to
the declared result type of function F. But:
|
NamedFunctionRef [63,67] | F#n |
U{function(*)} |
InlineFunctionExpr [64,68] | function(P) {E} |
U{function(*)} |
MapConstructor [–,69] | map{"A":E, "B":F} |
U{function(*)} |
Postfix Lookup [–,49] | E ? K |
If the type of E is a map type map(K, V) or an
array type array(V) , then the U-type corresponding to the item
type of V; otherwise U{*} |
(Unary) Lookup [–,53] | ? K |
If the context item type is a map type map(K, V) or an array
type array(V) , then the U-type corresponding to the item type
of V; otherwise U{*} |
ArrowExpr [–,29] | X => F(Y, Z) |
The static type of the equivalent static or dynamic function call
F(X, Y, Z) |
SquareArrayConstructor [–,74] | [X, Y, ...] |
U{function(*)} |
CurlyArrayConstructor [–,75] | array{X, Y, ...} |
U{function(*)} |
Where the static type of an expression is
U{function(*)}, it is useful to retain additional information:
specifically, the signature of the function. This may be regarded as information
ancillary to the U-type of the expression; it does not play any role in operations
such as testing whether one U-type is a subtype of another, or forming the union of
two U-types. This ancillary information is available for a
NamedFunctionRef
, for an InlineFunctionExpr
, for a
MapConstructor
, for a FunctionCall
whose static type is
U{function(*)}, and for a VarRef
if the variable is bound
to any of the forgoing, or if it has a declared type corresponding to
U{function(*)}.
Note:
The special case type inference used for an AdditiveExpr
or
MultiplicativeExpr
appearing as a predicate is possible because if
an arithmetic operation within a predicate produces any other result, for example
an xs:duration
or xs:dateTime
, this would cause a type
error (on the grounds that an xs:duration
or xs:dateTime
has no effective boolean value), and static type inference only needs to consider
the type of non-error results. The benefit of this special rule is that filter
expressions such as /descendant::section[$i + 1]
can be recognized as
returning a singleton, and therefore as being striding, even
if the type of $i
is unknown.
An AxisStep
consists of either a ForwardStep
or ReverseStep
followed by zero or more predicates. The predicates have no effect on the inferred
type of the
AxisStep
.
The static type of an abbreviated step is the static type of its expansion, for example
the
static type of @*
is the same as the static type of attribute::*
.
Both the constructs ForwardStep
or ReverseStep
, in their
unabbreviated form, are written as Axis::NodeTest
. The static type depends
on both the Axis
and the NodeTest
, and also on the
context item type, determined as described in 19.2 Determining the Context Item Type.
If the context item type has an empty intersection with U{N}
(that is, if the context item type cannot be a node), then evaluation of the AxisStep
will always fail; it is permissible to raise a type error statically in this case,
but for the
sake of the analysis, the static type of the AxisStep
can be taken as U{}
.
In other cases, let CIT be the intersection of the context item type
with U{N}
.
Let K(A, CIT) be the set of reachable node kinds given an axis A (a U-type) as defined by the following table:
Axis | Reachable Node Kinds |
---|---|
self | CIT |
attribute | if CIT includes U{element()} then U{attribute()} else U{} |
namespace | if CIT includes U{element()} then U{namespace-node()} else U{} |
child, descendant | if CIT includes U{element()} or U{document-node()} then
U{element(), text(), comment(), processing-instruction()} else U{} |
following-sibling, preceding-sibling, following, preceding | if CIT is U{document-node()} then U{} else
U{element(), text(), comment(), processing-instruction()} |
parent, ancestor | if CIT is U{document-node()} then U{} else
U{element(), document-node()}
|
ancestor-or-self | the union of K(ancestor, CIT) and CIT |
descendant-or-self | the union of K(descendant, CIT) and CIT |
Let T(NT)
be the set of node kinds that are capable of satisfying a NodeTest
NT,
defined by the following table:
NodeTest | Possible Node Kinds |
---|---|
AnyKindTest (that is, node() )
|
U{N} (that is, any node) |
Any other KindTest |
The corresponding U-type (for example, U{text()}
for the KindTest text() )
|
NameTest | The U-type corresponding to the principal node kind of the specified axis |
The static type of an AxisStep
with axis A and node test NT
,
given a context item type CIT, is then defined to be the
intersection of K(A, CIT)
with T(NT)
.
current
The rules in this section define the static type of a call to the current
function.
If the call is within a pattern, the static type of the function call is the match type of the pattern.
Note:
There is no circularity in this definition: a call to current
in a pattern can only appear within a predicate, and
the match type of a pattern never depends on anything appearing in a predicate.
Otherwise (the function call is within an XPath expression), the static type of the function call is the context item type that applies to the outermost containing XPath expression, determined by the rules in 19.2 Determining the Context Item Type.
Note:
The streamability analysis in this chapter is not schema-aware. There are cases where use of schema type information might enable a processor to determine that a construct is streamable when it would be unable to make this determination otherwise. Two examples:
A processor might decide that a construct such as price +
salesTax
is streamable if both the child elements have a simple
type such as xs:decimal
, or if the order in which they appear
in the input document is known.
A processor might decide that a step using the descendant axis, such as
.//title
, has striding rather than
crawling
posture if it can establish that two title
elements will never be nested
(that is, a title
cannot contain another title
).
This would allow the instruction <xsl:apply-templates
select=".//title"/>
to be used in a streaming template rule.
Although such constructs are not guaranteed streamable according to this specification, there is nothing to prevent a processor providing a streamed implementation if it is able to do so.
[Definition: For every expression, it is possible to establish by static analysis, information about the item type of the context item for evaluation of that expression. This is called the context item type of the expression.]
The context item type of an expression is a U-type.
The semantics of every construct, defined in
this specification or in the XPath specification, describe how the focus for evaluating each operand of the construct
is determined. In most cases the focus is the same as that of the parent construct.
In some cases the focus is determined by evaluating some other expression, for
example in the expressions A/B
, A!B
, or A[B]
,
the focus for evaluating B is A. More generally:
[Definition: A focus-changing construct is a construct that has one or more operands that are evaluated with a different focus from the parent construct.]
Note:
Examples of focus-changing constructs include the instructions
xsl:for-each
, xsl:iterate
, and
xsl:for-each-group
; path expressions, filter
expressions, and simple mapping expressions; and all patterns.
[Definition: Within a focus-changing construct there is in many cases one operand whose value determines the focus for evaluating other operands; this is referred to as the controlling operand.]
Note:
For example, the controlling operand of an xsl:for-each
,
xsl:iterate
, or xsl:for-each-group
instruction is the expression in its select
attribute; the
controlling operand of a filter expression E[P]
is
E
, and the controlling operand of a simple mapping
expression A!B
is A
.
[Definition: Within a focus-changing construct there are one or more operands that are evaluated with a focus determined by the controlling operand
(or in some cases such as
xsl:on-completion
, with an absent
focus); these are referred to as
controlled operands.]
Note:
For example, the main controlled operand of an
xsl:for-each
, xsl:iterate
, or
xsl:for-each-group
instruction is the contained sequence
constructor; the controlled operand of a filter expression E[P]
is P
, and the controlled operand of a simple mapping expression
A!B
is B
.
[Definition: The
focus-setting container of a construct C is the
innermost focus-changing construct
F (if one exists) such that C is directly or
indirectly contained in a controlled operand of
F. If there is no such construct
F, then the focus-setting container is the containing
declaration, for example an
xsl:function
or xsl:template
element.]
Note:
For example, if an instruction appears as a child of
xsl:for-each
, then its focus-setting container is the
xsl:for-each
instruction; if an expression appears
within the predicate of a filter expression, its focus-setting container is
the filter expression.
The context item type of a construct C is the first of the following that applies:
If the focus-setting container of C is an
xsl:function
element, an inline function declaration, or an
xsl:on-completion
element, then the context item type is
U{}
.
Note:
This is essentially an error case; expressions that depend on the focus should not normally appear within a construct that sets the focus to absent.
If the focus-setting container of C is an
xsl:source-document
instruction, then the context item type is U{document-node()}
.
If the focus-setting container of C is a template rule, then the context item type is the match type of the match pattern of the template rule, defined below.
If the focus-setting container of C is a
PredicatePattern
, then the context item type is U{*}
.
If the focus-setting container is a global variable
declaration, the context item type is determined by the type
attribute
of the xsl:global-context-item
declaration, defaulting to U{*}
,
or U{}
if the xsl:global-context-item
declaration specifies
use="absent"
.
If the focus-setting container is any other declaration, for example xsl:key
or
xsl:accumulator
, the
context item type is U{*}
.
Otherwise, the context item type is the static type (see 19.1 Determining the Static Type of a Construct) of the controlling operand of the focus-setting container of C.
[Definition: The
match type of a pattern is the most specific
U-type that is known to match all items that the pattern can
match.] The match type of a pattern is the inferred static type of the pattern’s equivalent expression, determined
according to the rules in 19.1 Determining the Static Type of a Construct. For example, the
match type of the pattern para[1]
is U{element()}
, while
that of the pattern @code[.='x']
is U{attribute()}
An operand role gives information about the operands of a particular kind of construct. The two important properties of an operand role are the required type and the operand usage.
The usage of an operand role is relevant only when the value of an operand supplied in that role is a node, or a sequence that contains nodes. It is one of the following:
[Definition: An operand usage of
absorption indicates that the construct reads the subtree(s)
rooted at a supplied node(s).] Examples are constructs that atomize
their operands, or that obtain the string
value of a supplied node, or that copy the supplied node to a new tree. Another
example is the deep-equal
FO30 function, which compares the
subtrees rooted at the nodes supplied in its first two arguments.
[Definition: An operand usage of
inspection indicates that the construct accesses properties
of a supplied node that are available without reading its subtree.]
Examples are functions such as name
FO30 and
base-uri
FO30, and the instance of
expression
which tests the type of a node (or other item), or functions such as
count
FO30, exists
FO30, and
boolean
FO30 which are only interested in the existence of
the node, and not in its properties.
[Definition: An operand usage of transmission indicates that the construct will (potentially) return a supplied node as part of its result to the calling construct (that is, to its parent in the construct tree).] It also indicates that document order is preserved: if the input is in document order, then the result must be in document order. An example is a filter expression, where nodes in the base expression (the expression being filtered) will typically appear in the result of the filter expression, in their original order.
[Definition: An operand usage of
navigation indicates that the construct may navigate freely
from the supplied node to other nodes in the same tree, in a way that is not
constrained by the streamability rules.] This covers several cases:
cases where it is known that the construct performs impermissible navigation
(for example, the xsl:number
instruction) or reordering (the
reverse
FO30 function), or that require look-ahead (the
innermost
FO30 function) and also cases where the analysis
is unable to determine what use is made of the node, for example because it is
passed as an argument to a user-defined function, or retained in a
variable.
The concept of operand usage is not used for all constructs (for example, it is not used in the analysis of path expressions). Where it is used, the assignment of operand usages to each operand role of a construct is defined in 19.8 Classifying Constructs.
Consider the following construct:
<xsl:source-document streamable="yes" href="emps.xml"> <xsl:for-each select="*/emp"> <xsl:value-of select="."/> </xsl:for-each> </xsl:source-document>
To assess the streamability, we follow the following logic:
The top-level construct is a sequence constructor. It is evaluated with a document node as the context item, and with a striding posture.
The sequence constructor has one child instruction, which has an operand usage of transmission.
The xsl:for-each
instruction evaluates its
select
expression, with the context item and posture unchanged.
The step child::*
is evaluated with this context item and
posture. The posture transition rules permit this; we now have a sequence
of child elements, and still a striding posture.
The same applies to the next step, child::emp
The content of the xsl:for-each
instruction is a
sequence constructor which itself has a single
operand, the xsl:value-of
instruction.
The xsl:value-of
instruction is evaluated once for each
emp
child, with that child as context item and in a
striding posture. This instruction uses the
general streamability rules. The operand usage of the select
expression is
absorption. This means that the result of the
xsl:value-of
instruction is grounded and consuming.
The result of the trivial sequence constructor contained in the
xsl:for-each
instruction is therefore grounded and consuming
The result of the xsl:for-each
instruction (see 19.8.4.18 Streamability of xsl:for-each) is therefore grounded and consuming
The result of the trivial sequence constructor contained in the
xsl:source-document
instruction is therefore grounded and consuming
The xsl:source-document
instruction is therefore guaranteed-streamable.
Now consider a slightly different construct:
<xsl:source-document streamable="yes" href="emps.xml"> <xsl:for-each select="*/emp"> <xsl:sequence select="."/> </xsl:for-each> </xsl:source-document>
To assess the streamability, we follow the following logic:
The top-level construct is a sequence constructor. It is evaluated with a document node as the context item, and with a striding posture.
The sequence constructor has one child instruction, which has an operand usage of transmission.
The xsl:for-each
instruction evaluates its
select
expression, with the context item and posture unchanged.
The step child::*
is evaluated with this context item and
posture. The posture transition rules permit this; we now have a sequence
of child elements, and still a striding posture.
The same applies to the next step, child::emp
The content of the xsl:for-each
instruction is a
sequence constructor which itself has a single
operand, the xsl:sequence
instruction.
The xsl:sequence
instruction is evaluated once for each
emp
child, with that child as context item and in a
striding posture. This instruction uses the
general streamability rules. The operand usage of the select
expression is
transmission. This means that the result of the
xsl:sequence
instruction is striding and motionless.
The result of the trivial sequence constructor contained in the
xsl:for-each
instruction is therefore also striding and motionless.
The result of the xsl:for-each
instruction (see 19.8.4.18 Streamability of xsl:for-each) is therefore striding and consuming (the wider of the sweeps of the
select
expression and the sequence
constructor).
The result of the trivial sequence constructor contained in the
xsl:source-document
instruction is therefore striding and consuming.
Since the result is not grounded, the xsl:source-document
instruction is therefore not guaranteed-streamable.
Expressed informally, the result of a declared-streamable
xsl:source-document
instruction
(or of a declared-streamable template rule)
must not contain streamed nodes. The reason
for this is that once streamed nodes are returned to constructs that are not
declared streamable and therefore have no streamability constraints, there is
no way to analyze what happens to them, and thus to guarantee
streamability.
Consider the expression .//chapter
.
When this appears as an argument to the function count
FO30
or exists
FO30, it can be streamed (it is a consuming expression, meaning that the subtree rooted at the
context item needs to be read in order to evaluate the expression). A possible
strategy for performing a streamed evaluation is to read all descendants of the
context item in document order, checking each one to see whether its name is
chapter
. The sweep of the expression will
be consuming, and its posture will be
crawling.
The operand usage (the usage of the argument to
count
FO30 or exists
FO30) is defined as
inspection. The general streamability rules show that when the posture of an
operand is crawling and the operand usage is inspection, the resulting
expression is grounded
and consuming. This means that (in the absence of other
consuming expressions) the containing template or function will generally be
streamable.
In the expression tail(.//chapter)
, the
operand usage is classified as transmission, meaning that the nodes are simply passed up the
tree to the next containing expression. In general, when a crawling expression is passed as an argument and the operand role
is transmission, the containing expression will also be
crawling. However, there is an exception where the
expression is known to deliver a singleton (for example,
head(.//chapter)
). In this case the returned sequence cannot
contain any nested nodes, so it is crawling.
When the same expression appears as an argument to an atomizing function
string-join
FO30, the processor knows that it will need to
access the subtree of each selected section
element in order to
compute the result of the function (the argument to
string-join
FO30 is classified as having operand usage
absorption). The processor does not know whether these
subtrees will be nested (one
section
might contain another). In most cases they will not be nested, because atomizing a
sequence that contains nested nodes is not generally a useful thing to do.
The streamability analysis therefore makes an optimistic assumption, by
treating atomization of a crawling expression as a
streamable operation. In the worst case, where it turns out that the
selected nodes are indeed nested, the processor must handle this, typically
by buffering the content of inner nodes until the end tag of the outer nodes
is reached.
This treatment of nodes in a crawling expression applies to all cases in which the content of
the nodes is handled in a way defined entirely by the rules of this
specification: for example, operations such as atomization, obtaining the
string value of nodes, deep copy of nodes, and the
deep-equal
FO30 function. It does not extend to cases
where the processing applied to the nodes is user-defined: for example,
operations such as xsl:apply-templates
,
xsl:for-each
, or xsl:for-each-group
. In
these cases, the nodes selected for processing must not be nested (a crawling posture is not permitted in these contexts).
When a crawling expression appears as an argument to a call on a user-defined function, the effect depends on the streamability category of the function, as described in 19.8.5 Classifying Stylesheet Functions.
The posture of a construct indicates the relationship of the nodes selected by the construct to a streamed input document. The value is one of the following:
[Definition: Grounded: indicates that
the value returned by the construct does not contain nodes from the streamed
input document]. Atomic values and function items are always
grounded; nodes are grounded if it is known that they are in a non-streamed
document. For example the expressions doc('x')
and
copy-of(.)
both return grounded nodes.
[Definition: Climbing: indicates that
streamed nodes returned by the construct are reached by navigating the parent,
ancestor[-or-self], attribute, and/or namespace axes from the node at the
current streaming position.] When the context posture is climbing, use of certain
axes such as parent
and ancestor
is permitted, but
use of other axes such as child
or descendant
violates the streamability rules.
[Definition: Crawling: typically
indicates that streamed nodes returned by a construct are reached by navigating the
descendant[-or-self] axis.] Nodes reached in this way are potentially nested (one might be an ancestor
of another), so further downward navigation is not permitted.
Expressions that can be statically determined to
return a singleton node (for example head(.//title)
) generate a
result with no such nesting, so
they are striding rather than crawling.
[Definition: Striding: indicates that
the result of a construct contains a sequence of streamed nodes, in document order,
that
are peers in the sense that none of them is an ancestor or descendant of any
other.] This is typically achieved by using one or more steps
involving the child or attribute
axes only. Use of the outermost
FO30 function can also result
in a striding posture, as can functions such as
head
FO30 or zero-or-one
FO30 that
ensure the result will be a singleton node.
[Definition: Roaming: indicates that
the nodes returned by an expression could be anywhere in the tree, which
inevitably means that the construct cannot be evaluated using
streaming.] For example, the posture of an axis
step using the following
or preceding
axis will
typically be roaming, which leads the analysis to conclude
that the construct is not streamable.
Note:
One way to think about the posture values is as labels for states in a finite
state automaton, where the alphabet of symbols accepted by the automaton is the
set of 13 XPath axes, and the sentence being parsed is a path expression
containing a sequence of axis steps. For example, use of the
descendant
axis when the current state is striding
moves the new state to crawling, and use of the parent
axis then takes it to climbing.
The posture of a construct is determined in one of several ways:
For axis steps, the posture of the expression is determined by the context posture and the choice of axis. For example, an axis step using the ancestor axis always has a posture of climbing, while an axis step using the child axis, if the context posture is striding, will itself have a posture of striding. The rules for the posture transitions produced by axis steps are given in 19.8.8.9 Streamability of Axis Steps.
For many other constructs, the posture is determined by the general streamability rules. These determine the result posture in terms of the operands of the construct and the way in which each operand is used. For example, a construct that accepts a streamed node as the value of an operand, and atomizes that node, will generally have a posture of grounded.
Other constructs have their own special rules, which are all listed in this
chapter. For example, a call on the root
FO30 function
behaves analogously to an axis step, and is described in 19.8.9.18 Streamability of the root Function. Special rules are needed for:
Constructs that evaluate an operand more than once,
such as an XPath for
expression;
Constructs that have alternatives among their operands, such as an XPath
if
expression;
Constructs that navigate relative to the context item, such as axis steps;
Constructs with implicit inputs, such as the context item expression
.
(dot);
Constructs that change the focus, such as a filter expression;
Constructs that invoke functions or templates.
The characterization of an expression as striding, crawling, climbing, or
roaming applies only to the streamed nodes in the the result of the expression. The
result of the expression
may also contain non-streamed (grounded) nodes or atomic values. For example
if /x/y
is a striding expression, then (/x/y | $doc//x)
is also striding, given
that $doc
contains non-streamed nodes. The assertion that the nodes in the result of a striding
expression are in document order and are peers thus applies only to the subset of
the nodes that are streamed.
Note:
A consequence of this is that when striding expressions are used in a context that
requires sorting into
document order, for example (/x/y | $doc//x) / @price
, the fact that the expression is striding
does not eliminate the need for the sequence to be re-ordered. However, there will
never be a need for the relative
order of the streamed nodes in the value to change.
Since the data model leaves the relative order of nodes in different trees implementation-defined, and since streamed and unstreamed nodes will necessarily be in different trees, a useful implementation strategy might be to arrange that streamed nodes always precede unstreamed nodes in document order (or vice versa). An operation that needs to process the result of a striding expression in document order can then first deliver all the streamed nodes (by consuming the input stream) in the order they arrive, and then deliver the unstreamed nodes, suitably sorted.
In the same way as the type of the context item can be determined for any construct C by reference to the type of the construct that establishes the context for the evaluation of C, so the posture of the context item C can be determined by reference to the posture of the construct that establishes the context.
The context posture of a construct C is the first of the following that applies:
If the focus-setting container of C is an
xsl:function
declaration, an inline function declaration,
or an xsl:on-completion
element, then the context posture is
roaming.
Note:
This is essentially an error case; expressions that depend on the context item should not normally appear within these constructs.
If the focus-setting container of C is an
xsl:source-document
instruction, then the context posture is
striding if the
instruction is declared-streamable, or grounded otherwise.
If the focus-setting container of C is a
template rule whose mode is declared with
streamable="yes"
, then the context posture is striding.
If the focus-setting container of C is a pattern, then the context posture is striding.
If the focus-setting container of C is an
xsl:attribute-set
declaration with the attribute
streamable="yes"
, then the context posture is striding.
If the focus-setting container is any other declaration, for example a global variable declaration, a
named template, or a template rule or attribute set that
does not specify streamable="yes"
, then the context posture is
roaming.
Otherwise, the context posture is the posture of the controlling operand of the focus-setting container of C.
[Definition: Every construct has a sweep, which is a measure of the extent to which the current position in the input stream moves during the evaluation of the expression. The sweep is one of: motionless, consuming, or free-ranging .] This list of values is ordered: a free-ranging expression has wider sweep than a consuming expression, which has wider sweep than a motionless expression.
[Definition: A motionless construct is any construct deemed motionless by the rules in this section (19 Streamability).] Informally, a motionless construct is one that can be evaluated without changing the current position in the input stream.
Note:
The context item expression .
is classified as motionless; however a
construct that uses .
as an operand (for example,
string(.)
) might be consuming. The
streamability rules effectively consider expressions such as .
within
the context of the containing construct.
[Definition: A consuming construct is any construct deemed consuming by the rules in this section (19 Streamability).] Informally, a consuming construct is one whose evaluation requires repositioning of the input stream from the start of the current node to the end of the current node.
[Definition: A free-ranging construct is any construct deemed free-ranging by the rules in this section (19 Streamability).] Informally, a free-ranging construct is one whose evaluation may require access to information that is not available from the subtree rooted at the current node, together with information about ancestors of the current node and their attributes.
The table below shows some examples of expressions having different combinations of posture and sweep.
Motionless | Consuming | Free-Ranging | |
---|---|---|---|
Grounded | name() |
string(title) |
See Note |
Climbing | parent::* |
child::x/ancestor::y |
See Note |
Striding | @status |
child::* |
See Note |
Crawling | The subexpression . in //a/. |
descendant::* |
//x[child::y] |
Roaming | See Note | See Note | preceding::* |
Note:
In all cases where either the posture is roaming, or the sweep is free-ranging, or both, the effect is to make an expression non-streamable. For convenience, therefore, evaluation of the streamability rules in most cases returns the values roaming and free-ranging only in combination with each other. In cases where the rules return a posture of roaming combined with some other sweep, or a sweep of free-ranging with some other posture, the final result of the analysis is always the same as if the expression were both roaming and free-ranging.
For an example of a case where an expression is roaming but
not free-ranging, consider the right-hand operand of the
relative path expression (preceding::x/.)
. The rules for the
streamability of a context item expression (see 19.8.8.13 Streamability of the Context Item Expression) give ".
" in this
context a roaming posture, combined with motionless sweep. But the relative path expression as a whole is
roaming and free-ranging (see 19.8.8.8 Streamability of Path Expressions), so the apparent inconsistency is
transient.
A construct is grounded if the items it delivers do not include nodes from a streamed document; it is consuming if evaluation of the construct reads nodes from a streamed input in a way that requires advancing the current position in the input.
Grounded consuming constructs play an important role in streaming, and this section discusses some of their characteristics.
Examples of grounded consuming constructs (assuming the context item is a streamed node) include:
sum(.//transaction/@value)
copy-of(./account/history/event)
distinct-values(./account/@account-nr)
<xsl:for-each select="transaction"><t><xsl:value-of select="@value"/></t></xsl:for-each>
XSLT 3.0 provides the two functions copy-of
and snapshot
with the explicit purpose of creating a sequence of grounded nodes, that can be processed
one-by-one without the usual restrictions that apply to streamed processing, such
as the
rule permitting at most one downward selection. The processing style that exploits
these
functions is often called “windowed streaming”.
In general the result of a grounded consuming construct is a sequence. Depending on how this sequence is used, it may or may not be necessary for the processor to allocate sufficient memory to hold the entire sequence. The streamability rules in this specification place few constraints on how a grounded sequence is used. This is deliberate, because it gives users control: by creating a grounded sequence (for example, by use of the copy-of function) stylesheet authors create the possibility to process data in arbitrary ways (for example, by sorting the sequence), and accept the possibility that this may consume memory.
Pipelined evaluation of a sequence is analogous to streamed processing of a source
document.
Pipelined evaluation occurs when the items in a sequence can be processed one-by-one,
without
materializing the entire sequence in memory. Pipelining is a common optimization technique
in
all functional programming languages. Operations for which pipelined evaluation is
commonly
performed include filtering ($transactions[@value gt 1000]
), mapping
($transactions!(@value - @processing-fee)
), and aggregation
(sum($transactions)
). Operations that cannot be pipelined (because,
for example, the first item in the result sequence cannot be computed without knowing
the last item in the input sequence) include those that change the order of items
(reverse()
, sort()
). Other operations such as distinct-values()
allow the input to be processed one item at a time, but require memory that potentially
increases as the sequence length increases. Saving a grounded sequence in a variable
is
also likely in many cases to require allocation of memory to hold the entire sequence.
When the input to an operation is a grounded consuming sequence (more accurately, a sequence resulting from the evaluation of a grounded consuming construct), this specification does not attempt to dictate whether the operation is pipelined or not. The goal of interoperable streaming in finite memory can therefore only be achieved if stylesheet authors take care to avoid constructing grounded sequences that occupy large amounts of memory. In practice, however, users can expect that many grounded consuming constructs will be pipelined where the semantics permit this.
Note:
Some processors may recognize an opportunity for pipelining only if the expression
is written in a particular way. For example the constructs copy-of(/a/b/c)
and
/a/b/c/copy-of(.)
are to all intents and purposes equivalent, but some processors
might recognize the second form more easily as suitable for pipelining.
(There is one minor difference between these expressions: the order of nodes in copy-of(/a/b/c)
is required to reflect the document order of the nodes in /a/b/c
, while the result
of /a/b/c/copy-of(.)
can be in any order, in consequence of the rule that document order
for nodes in different trees is implementation-dependent.)
The use of the last
FO30 function requires particular care because of
its effect on pipelining. The streamability rules prevent the use of last()
in
conjunction with an expression that returns streamed nodes (because it would require
look-ahead
in the stream), but there is no similar constraint for grounded sequences. So for
example it
is not permitted (in a context that requires streaming) to write
<xsl:for-each select="transaction"> <xsl:value-of select="position(), ' of ', last()"/> </xsl:for-each>
but it is quite permissible to write
<xsl:for-each select="transaction/copy-of()"> <xsl:value-of select="position(), ' of ', last()"/> </xsl:for-each>
because the call on copy-of
makes the sequence grounded. This construct
cannot be pipelined because computing the first item in the result sequence depends
on knowing
the length of the input sequence; in consequence, a processor might be obliged to
buffer all
the transactions (or their copies) in memory.
In this simple example the impact of the call on last
FO30 is easily detected
both by the human reader and by the XSLT processor, but there are other cases where
the effect
is less obvious. For example if the stylesheet executes the instruction
<xsl:apply-templates select="transaction/copy-of(.)"/>
then the presence of a call on last
FO30 in one of the template rules
that gets invoked might not be easily spotted; yet the effect is exactly the same
in preventing the result being computed by processing input items strictly one at
a time. Avoiding such effects is entirely the responsibility of the stylesheet author.
By contrast, there is no intrinsic reason why use of the position
FO30 should
prevent pipelined processing: all it requires is for the processor to count how many
items have been
processed so far. Processors may also be able to handle the construct position() = last()
without storing the entire sequence in memory; rather than actually evaluating the
numeric values of
position()
and last()
, this can be done by testing whether the context item
is the last item in the sequence, which only requires a one-item lookahead.
This section defines the properties of every kind of construct that may appear in a stylesheet. It identifies the operand roles and their usage, and it gives the rules that define the posture and sweep of the construct. In cases where the general streamability rules apply, there is still an entry for the construct in order to define its operands and their usages, since this information is needed by the general rules.
The following sections describe this categorization for each kind of construct:
Sequence constructors: see 19.8.3 Classifying Sequence Constructors
Instructions: see 19.8.4 Classifying Instructions
Stylesheet functions: see 19.8.5 Classifying Stylesheet Functions
Attribute sets: see 19.8.6 Classifying Attribute Sets
Value templates: see 19.8.7 Classifying Value Templates
Expressions: see 19.8.8 Classifying Expressions
Patterns: see 19.8.10 Classifying Patterns
Calls to built-in functions: see 19.8.9 Classifying Calls to Built-In Functions
[Definition: Many constructs share the same streamability rules. These rules, referred to as the general streamability rules, are defined here.]
Examples of constructs that use these rules are: an arithmetic expression, an
attribute value template, a sequence constructor, the xsl:value-of
instruction,
and a call to the doc
FO30 function.
The rules determine both the posture and sweep of a construct. To determine the posture and sweep of a construct C, assuming these general rules are applicable to that kind of construct:
For each operand of C:
Establish:
The static type T of the operand (see 19.1 Determining the Static Type of a Construct).
Note:
The static type is a U-type. For example,
the static type of the expression (@*, *)
is
U{element(), attribute()}.
The sweep S and posture P of the operand (by applying the rules in this section 19.8 Classifying Constructs to that operand, recursively).
The operand usage U corresponding to the role of the operand within C (from the information in this section 19.8 Classifying Constructs).
Compute the adjusted sweep S′ of the operand by taking the first of the following that applies:
If S is free-ranging or P is roaming, then S′ is free-ranging. (In this case the posture and sweep of C are roaming and free-ranging, regardless of any other operands.)
If P is grounded, then S′ is S.
Otherwise (P is not grounded, which implies that the operand is capable of returning streamed nodes), compute S′ as follows:
Compute the adjusted usage U′ as follows:
If U is absorption and the intersection of T with U{element(), document-node()} is U{} (that is, if T is a type that does not allow nodes with children), then U′ is inspection.
Note:
This is because the entire subtree of nodes such as text nodes is available without reading further data from the input stream.
Otherwise, U′ is U.
Compute the adjusted sweep S′ from the table below:
Posture (P) | Adjusted Usage (U') | |||
---|---|---|---|---|
Absorption | Inspection | Transmission | Navigation | |
Climbing | Free-ranging | S | S | Free-ranging |
Striding | Consuming | S | S | Free-ranging |
Crawling | Consuming | S | S | Free-ranging |
[Definition: An operand is potentially consuming if at least one of the following conditions applies:
The operand usage is transmission and the operand is not grounded.
]
Having computed the adjusted sweep S′(o) of each operand o, the posture and sweep of C are the first of the following that applies:
If C has no operands, then grounded and motionless.
If any operand o has an adjusted sweep S′(o) of free-ranging, then roaming and free-ranging.
If more than one operand is potentially consuming, then:
If all these operands form part of a choice operand group, then the posture of C is the combined posture of the operands in this group, and the sweep of C is the widest sweep of the operands in this group
If all these operands have S′ = motionless, (which necessarily means they have U′ = U = transmission) and if they all have the same posture P0, then motionless with posture P0.
Note:
For example, the expression (@a, @b)
is
motionless and striding.
Otherwise, roaming and free-ranging.
If exactly one operand o is potentially consuming, then:
If o is a higher-order operand of C, then roaming and free-ranging.
If the operand usage of o is absorption or inspection, then grounded and consuming.
If the posture of o is crawling and C is a function call of a built-in function whose signature indicates a return type with a maximum cardinality of one then striding and the adjusted sweep of o.
Note:
Although this rule is written in
general terms, the only functions that it applies to (at the
time of publication) are head
FO30,
exactly-one
FO30, and
zero-or-one
FO30. This rule only
applies if the argument usage is transmission (other cases
having been handled by earlier rules); of the built-in
functions, the three functions listed are the only ones
having an argument with usage transmission and a return type
with maximum cardinality one.
Otherwise (the operand usage of o is transmission), the posture and adjusted sweep of o.
Otherwise (all operands are motionless) grounded and motionless.
Note:
The rules ensure that if more than one operand is consuming, that is, if more than one operand reads the subtree of the context node in a way that would cause the current position of the input stream to change, then the construct is not streamable.
The rules also prevent multiple streamed nodes being returned in the result of
an expression if they are delivered by
different operands. For example, the expression count((..,
*))
is not guaranteed streamable. This is to make static analysis
possible: the posture needs to be statically determined to ensure that
streaming does not fail at execution time. It is permitted, however, for
streamed nodes to be mixed in a sequence with non-streamed nodes or with atomic
values; in this case the posture of the result will be that of the streamed
nodes. It is also permitted to have multiple
operands delivering streamed nodes in different branches of a conditional,
provided the sweep and posture are compatible: for example if (X) then
@name else name
is guaranteed streamable.
Expressions that have more than one operand
with usage transmission, for example (A, B)
,
or (A | B)
, or insert-before(A, n, B)
, generally allow only one of these operands to select
streamed nodes. The result of the expression will contain
a mixture of streamed and grounded nodes, but its posture and sweep will be
that of the streamed operand. The nodes in the result will not necessarily be in document
order,
but the subset of the nodes that are streamed will always be in document order.
This section provides some examples of how the general streamability rules operate. In each example, the emphasis is on the outermost construct shown; explanations for how the sweep and posture of its operands are derived are not given, though in many cases they are explained in earlier examples.
The examples assume that the context item type for evaluation of the expression shown is an element node, and that its posture is striding.
2 + 2
is grounded and motionless, because both the operands are
grounded and motionless.
price * 2
is grounded and consuming, because one of the
operands is consuming and the relevant operand usage is absorption.
price - discount
is roaming and free-ranging, because both the
operands are consuming (and they are not members of a parallel operand
group).
price * @discount
is grounded and consuming. The left-hand operand is consuming and
the corresponding operand usage is absorption, while the right-hand operand is motionless, again with an
operand usage of absorption, and its item type is attribute()
which changes the effective usage to inspection.
a/b/c
is striding and consuming. This is determined not by the
general streamability rules, but by the rules for path expressions in
19.8.8.8 Streamability of Path Expressions.
a//c
is crawling and consuming. This is similarly determined by
the rules for path expressions in 19.8.8.8 Streamability of Path Expressions.
count(a/b/c)
is grounded and consuming, because the operand
(the argument to the count function) is striding and consuming (see earlier
example) and the operand usage is inspection.
sum(a/b/c)
is grounded and consuming, because the operand (the
argument to the sum
function) is striding and consuming (see earlier example) and the operand
usage is absorption.
count(descendant::c)
is grounded and
consuming, because the operand (the argument to the count
function) is crawling and consuming (see earlier example) and the operand
usage is inspection.
tail(descendant::c)
is crawling and
consuming. The operand is crawling, the operand usage is transmission, so
the posture and sweep of the result are the same as the posture and sweep of
the consuming operand.
unordered(a|b)
is crawling and
consuming. The operand (the argument to the unordered
function)
is crawling (see 19.8.8.4 Streamability of union, intersect, and
except Expressions), and
the operand usage is transmission, so the posture and sweep of the result
are the same as the posture and sweep of the consuming operand.
zero-or-one(descendant::c)
is
striding and consuming. Although the operand is crawling, the operand usage
is transmission and the cardinality of the expression is zero or one, so the
posture of the result is striding. The same analysis applies to
exactly-one(descendant::c)
and to
head(descendant::c)
.
sum(descendant::c)
is grounded and
consuming, because the operand (the argument to the sum
function) is crawling and consuming (see earlier example) and the operand
usage is absorption. In theory (although it is unlikely in practice) the
selected c
elements might be
nested one inside another. The processor is expected to handle
this situation, which may require some buffering. For example, given the
untyped source document
<a><c><c>1</c><c>2</c><c>3</c></c></a>
, the
result of the expression is 129
(123 + 1 + 2 + 3), and to
evaluate this, a streaming processor will typically maintain a stack of
buffers to accumulate the typed values of each of the four c
elements during a single pass of the source document.
"Q{" || namespace-uri(.) || "}" || local-name(.)
is grounded
and motionless. The two literal operands are grounded and motionless because
they have no operands; the two function calls are grounded and motionless
because they have a single operand that is striding and motionless, with an
operand usage of inspection.
copy-of(.)/head/following-sibling::*
is grounded and consuming.
The left-hand operand
copy-of(.)/head
is grounded and consuming because, under the
rules in 19.8.8.8 Streamability of Path Expressions, its left-hand operand
copy-of(.)
is grounded and consuming. This in turn is
because .
is striding and motionless, and the operand usage is
absorption.
if ($discounted) then price else discounted-price
is striding
and consuming, because the two branches of the conditional are both striding
and consuming, and they form a choice operand group with
usage transmission.
if ($gratis) then 0 else price
is striding and consuming
because there is only one consuming operand (the fact that it is part of a
choice operand group does not affect the
reasoning).
count((author, editor))
is roaming and free-ranging. The first
argument to the count
function is an expression with two
operands, both having usage=transmission, and neither being grounded.
count((author | editor))
is grounded and consuming. A union
expression is not subject to the general streamability rules; it has its own
rules, defined in 19.8.8.4 Streamability of union, intersect, and
except Expressions, which
establish in this case that the argument to the count
FO30
is crawling and consuming. The
count
FO30 function does follow the general
streamability rules, with an operand usage of inspection: under rule 1(b)(iii)(B) the adjusted sweep is consuming, and rule 2(d)(iii) then applies.
('{', author, '}')
is striding and consuming. Exactly one
operand is consuming; it has usage transmission, so the
result has the posture and sweep of that operand. (The formal analysis
treats comma as a binary operator, but the same result can be obtained by
treating the content of the parenthesized expression as an expression with
three operands.)
The posture and sweep of a sequence constructor are determined by the general streamability rules.
The operand roles and their usages are:
The immediately contained
instructions
and literal result elements,
including any xsl:on-empty
or
xsl:on-non-empty
instructions. The operand usage for these operands is transmission.
Any text value templates appearing in text nodes within the sequence constructor, if text value templates are enabled. The operand usage for these operands is absorption.
Note:
Some consequences of these rules are:
An empty sequence constructor is motionless, and its posture is grounded.
A sequence constructor containing a single instruction has the same sweep and posture as that instruction. (This means that sequence constructors containing a single instruction can usefully be dropped from the construct tree.)
Informally, a sequence constructor is not streamable if it contains more than one instruction that moves the position of the input stream.
xsl:on-empty
or xsl:on-non-empty
instructions are not treated specially. For example, there is no attempt
to take into account that they are mutually exclusive: if one is
evaluated, the other will not be evaluated. In most use cases for these
instructions, they will be motionless, so the additional complexity of
doing more advanced analysis would rarely be justified.
This section describes how instructions are classified with respect to their streamability. The criteria are given first for literal result elements and extension instructions,, then for each XSLT instruction, listed alphabetically.
The posture and sweep of a literal result element follow the general streamability rules. The operand roles and their usages are:
The contained sequence constructor (usage absorption)
Any expressions contained in attribute value templates among the literal result element’s attributes (usage absorption)
Any attribute sets named in the
xsl:use-attribute-sets
attribute (usage irrelevant, but can be taken as inspection).
Note:
In practice, a reference to an attribute set that is declared-streamable does not affect the analysis, while a reference to any other attribute set makes the literal result element roaming and free-ranging.
For a processor that recognizes an extension instruction, the posture and sweep of the instruction are implementation-defined.
For a processor that does not recognize an extension instruction, the posture and sweep of the instruction are determined by applying the general streamability rules, The operand roles and their usages are:
The sequence
constructors contained in any xsl:fallback
children (usage transmission)
Instructions in the XSLT namespace that are present under the provisions for forwards compatible behavior are treated in the same way as unrecognized extension instructions.
Note:
These rules mean that if there is no xsl:fallback
child
instruction, the containing construct will be classified as streamable.
However, any attempt to execute the instruction will lead to a dynamic
error, so in fact, neither streamed nor unstreamed evaluation is
possible.
xsl:analyze-string
The posture and sweep of
xsl:analyze-string
follow the general streamability rules. The operand roles and their usages are:
the select
expression (usage absorption);
the regex
attribute value template (usage absorption);
the sequence constructors contained in the
xsl:matching-substring
and
xsl:non-matching-substring
elements. These have usage
navigation, because they can be evaluated more
than once. The context posture for the two sequence
constructors is grounded, reflecting the fact that
their context item type is xs:string
.
Note:
In practice, the sweep of the
instruction will usually be the same as the sweep of the select
expression, and its posture will be grounded. Exceptions occur for example if the
regex
attribute is not motionless, or if
the contained sequence constructors refer to a grouping variable bound in a
contained xsl:for-each-group
instruction.
xsl:apply-imports
The rules in this section apply also to xsl:next-match
.
The posture and sweep of these two instructions follow the general streamability rules. The operand roles and their usages are:
An implicit operand: a context item expression (.
), with
usage absorption;
The select
attribute or contained sequence constructor of each
xsl:with-param
child element, with type-determined usage based on the type declared in the
xsl:with-param/@as
attribute, or item()*
if
absent.
xsl:apply-templates
If there is no select
attribute, the following
analysis assumes the presence of an implicit operand
select="child::node()"
.
The posture and sweep of the
xsl:apply-templates
instruction are the first of the
following that apply:
If the select
expression is grounded,
then the posture and sweep of the
xsl:apply-templates
instruction follow the general streamability rules, with the operand roles and their usages as follows:
The select
expression (the operand usage is irrelevant, but can be taken as
absorption)
The select
expressions and contained sequence
constructors of any child xsl:with-param
elements
(usage type-determined, based on the type in the
xsl:with-param/@as
attribute, defaulting to
item()*
)
Any attribute value templates appearing in attributes of a child
xsl:sort
instruction (usage absorption)
The select
expression or contained sequence
constructor of any xsl:sort
children, assessed
with a context posture of grounded (usage absorption).
For example, <xsl:apply-templates
select="copy-of(.)"/>
is grounded and
consuming.
If there is an xsl:sort
child element, then roaming and free-ranging.
If the implicit or explicit mode
attribute identifies a
mode that is not declared with
streamable="yes"
, then roaming and free-ranging.
Note:
When mode="#current"
is specified, this is treated as
equivalent to specifying a streamable mode; although it is not known
statically what the mode will be, it is always the case that if the
template is invoked with a streamed node as the context item, then the
current mode must be a streamable mode.
If the select
expression is climbing or
crawling, then roaming and
free-ranging
Otherwise, the posture and sweep
of the xsl:apply-templates
instruction follow the
general streamability rules. The operand roles and their usages are as follows:
The (explicit or implicit) select
expression, with
usage absorption;
The select
attribute or contained sequence constructor of each
xsl:with-param
child element, with type-determined usage based on the type declared in
the xsl:with-param/@as
attribute, or
item()*
if absent.
xsl:assert
The posture and sweep of
xsl:assert
follow the general streamability rules. The operand roles and their usages are as follows:
The test
expression (usage inspection)
The select
expression (usage absorption)
The error-code
attribute value template (usage absorption)
The contained sequence constructor (usage absorption).
xsl:attribute
The posture and sweep of
xsl:attribute
follow the general streamability rules. The operand roles and their usages are as follows:
The name
attribute value template (usage absorption)
The namespace
attribute value template (usage absorption)
The select
expression (usage absorption)
The separator
attribute value template (usage absorption)
The contained sequence constructor (usage absorption).
xsl:break
The posture and sweep of
xsl:break
follow the general streamability rules. The operand roles and their usages are as follows:
The select
expression (usage transmission)
The contained sequence constructor (usage transmission).
xsl:call-template
The posture and sweep of
xsl:call-template
follow the general streamability rules. The operand roles and their usages are as follows:
Unless the referenced template has a child
xsl:context-item
element with the attribute
use="prohibited"
, there is an implicit operand, a context
item expression (.
): its operand usage
is the type-determined usage based on the type
declared in the xsl:context-item/@as
attribute of the target
named template, defaulting to item()*
if absent.
The select
expression or sequence constructor content of any
contained xsl:with-param
child element: its operand usage is the type-determined usage based on the type declared in the
xsl:with-param/@as
attribute, or the
xsl:param/@as
attribute of the corresponding parameter on
the target named template, whichever is more restrictive, defaulting to
item()*
if both are absent.
Note:
Calling xsl:call-template
will usually make stylesheet code
unstreamable if a streamed node is passed explicitly or implicitly to the
called template, unless it is atomized by declaring the expected type to be
atomic.
xsl:choose
The posture and sweep of
xsl:choose
follow the general streamability rules. The operand roles and their usages are as follows:
The test
attribute of contained xsl:when
elements (usage inspection).
The sequence constructors contained within xsl:when
and
xsl:otherwise
child elements (usage transmission). These sequence constructor operands form a
choice operand group.
Note:
The effect is to allow either of the following:
Any or all of the sequence constructors in xsl:when
and
xsl:otherwise
branch may be consuming, in
which case the test
expressions must all be motionless.
Any one of the test
expressions may be consuming,
in which case all the other test
expressions, and all the sequence constructors, must be motionless.
xsl:comment
The posture and sweep of
xsl:comment
follow the general streamability rules. The operand roles and their usages are as follows:
The select
expression (usage absorption)
The contained sequence constructor (usage absorption).
xsl:copy
The posture and sweep of
xsl:copy
follow the general streamability rules. The operand roles and their usages are as follows:
The expression in the select
attribute, defaulting to a
context item expression (.
) (usage inspection)
The contained sequence constructor (usage absorption), assessed with context posture and context item
type based on the select
expression if present, or the outer
focus otherwise.
Any attribute sets named in the
use-attribute-sets
attribute (usage irrelevant, but can be taken as inspection).
Note:
In practice, a reference to an attribute set that is declared-streamable does not
affect the analysis, while a reference to any other attribute set makes the xsl:copy
instruction
roaming and free-ranging.
Note:
The effect of these rules is that when a select
attribute is present, the sequence constructor contained by the xsl:copy
instruction is deemed to be a higher-order operand of the instruction,
even though it can only be evaluated once.
This has the practical consequence that the following example is not guaranteed-streamable, even though it is possible to imagine a strategy for streamed evaluation:
<xsl:for-each-group select="product" group-adjacent="@category"> <xsl:copy select=".."> <xsl:copy-of select="current-group()"/> </xsl:copy> </xsl:for-each-group>
A workaround in this case might be to rewrite the code as follows:
<xsl:for-each-group select="product" group-adjacent="@category"> <xsl:element name="{name(..)}" namespace-uri="{namespace-uri(..)}"> <xsl:copy-of select="current-group()"/> </xsl:element> </xsl:for-each-group>
xsl:copy-of
The posture and sweep of
xsl:copy-of
follow the general streamability rules. The operand roles and their usages are as follows:
The select
expression (usage absorption).
xsl:document
The posture and sweep of
xsl:document
follow the general streamability rules. The operand roles and their usages are as follows:
The contained sequence constructor (usage absorption).
xsl:element
The posture and sweep of
xsl:element
follow the general streamability rules. The operand roles and their usages are as follows:
The name
attribute value template (usage absorption)
The namespace
attribute value template (usage absorption)
Any attribute sets named in the
use-attribute-sets
attribute (usage irrelevant, but can be taken as inspection).
Note:
In practice, a reference to an attribute set that is declared-streamable does not
affect the analysis, while a reference to any other attribute set makes the xsl:element
instruction
roaming and free-ranging.
The contained sequence constructor (usage absorption).
xsl:evaluate
The posture and sweep of
xsl:evaluate
follow the general streamability rules. The operand roles and their usages are as follows:
The xpath
expression (usage absorption)
The context-item
expression (usage navigation)
The with-params
expression (usage navigation)
The base-uri
attribute value template (usage absorption)
The namespace-context
expression (usage inspection)
The schema-aware
attribute value template (usage absorption)
The select
attributes and contained sequence constructors of any
xsl:with-param
child elements (usage type-determined, based on the
type in the xsl:with-param/@as
attribute, defaulting to
item()*
)
Note:
In practice, code containing an xsl:evaluate
instruction
will usually be streamable provided that streamed nodes are not passed to
the dynamic expression either as the context item or as the value of a
parameter.
xsl:fallback
The posture and sweep of the
xsl:fallback
instruction depend on whether the processor is
performing fallback (which is known statically).
If the processor is performing fallback, then the posture
and sweep of the xsl:fallback
instruction
are the posture and sweep of the contained sequence constructor.
If the processor is not performing fallback, then the instruction is grounded and motionless.
xsl:for-each
The posture and sweep of the
xsl:for-each
instruction are the first of the following
that applies:
If the select
expression is grounded,
then the posture and sweep of the
xsl:for-each
instruction follow the general streamability rules, with the operand roles and their usages as follows:
The select
expression (the operand usage is irrelevant, but can be taken as
inspection)
The contained sequence constructor (usage transmission). This is a higher-order operand; its context posture is grounded.
Any attribute value templates appearing in attributes of a child
xsl:sort
instruction (usage absorption)
The select
expression or contained sequence
constructor of any xsl:sort
children, assessed
with a context posture of grounded (usage absorption).
These are higher-order
operands; their context posture is grounded.
If there is an xsl:sort
child element, then roaming and free-ranging.
If the posture of the
select
expression is crawling and the
sweep of the contained sequence constructor is consuming, then
roaming and free-ranging.
Otherwise:
The posture of the instruction is the posture of the contained sequence constructor, assessed with the context posture
and context item type set to the posture and
type of the select
expression.
The sweep of the instruction is the wider of
the sweep of the select
expression
and the sweep of the contained sequence constructor.
Note:
The ordering of sweep values is in increasing order: motionless, consuming, free-ranging.
Note:
Because the body of the xsl:for-each
instruction is a
higher-order operand of the instruction, any
variable reference within the body that is bound to a streaming parameter of a containing stylesheet function will not be singular, which in many
cases will make the entire function non-streamable.
xsl:for-each-group
The posture and sweep of the
xsl:for-each-group
instruction are the first of the
following that applies:
If the select
expression is grounded,
then the posture and sweep of the
xsl:for-each-group
instruction follow the general streamability rules, with the operand roles and their usages as follows:
The select
expression (the operand usage is irrelevant, but can be taken as
inspection)
The collation
attribute value template (usage absorption)
Any attribute value templates appearing in attributes of a child
xsl:sort
instruction (usage absorption)
The group-by
or group-adjacent
expression, assessed with a context posture of
grounded (usage absorption).
The select
expression or contained sequence
constructor of any xsl:sort
children, assessed
with a context posture of grounded (usage absorption).
The group-starting-with
or
group-ending-with
patterns if present; these are
higher-order
operands with usage inspection.
If there is a group-by
attribute and the instruction is not a child of
xsl:fork
, then roaming and free-ranging.
If there is a group-by
or
group-adjacent
attribute that is not motionless, then roaming and free-ranging.
If there is an xsl:sort
child element
and the instruction is not a child of xsl:fork
, then roaming and free-ranging.
If the posture of the
select
expression is crawling and the
sweep of the contained sequence constructor is consuming, then
roaming and free-ranging.
Otherwise:
The posture of the instruction is the posture of the contained sequence constructor, assessed with the context posture
and context item type set to the posture and
type of the select
expression.
The sweep of the instruction is the wider of
the sweeps of the
select
expression and the contained sequence constructor, where the ordering of
increasing width is motionless, consuming, free-ranging.
Note:
Because the body of the xsl:for-each-group
instruction is a higher-order operand of the
instruction, any variable reference within the body that is bound to a
streaming parameter of a containing stylesheet function will not be singular, which in many
cases will make the entire function non-streamable.
Note:
The above rules do not explicitly mention any
constraints on the presence or absence of a call on the
current-group
function. In practice, however, this
plays an important role. In the most common case, the select
expression of xsl:for-each-group
is likely to be striding,
for example an expression such as select="*"
. Any call on
current-group
associated with this
xsl:for-each-group
instruction will ordinarily be
striding and consuming, which is
consistent with streaming provided there is only one such call, and if it
appears in a suitable context (for example, not within a predicate). If
there is more than one call, or if it appears in an unsuitable context (for
example, within a predicate), then this will have the same effect as
multiple appearances of other consuming expressions: the construct as a
whole will be free-ranging. These rules are not spelled out explicitly, but
rather emerge as a consequence of the general streamability rules.
xsl:fork
The posture and sweep of
xsl:fork
are the first of the following that applies:
If there is a child xsl:for-each-group
instruction, then
the posture and the sweep of that
instruction.
If there are no child xsl:sequence
instructions (other than
xsl:fallback
), then grounded and
motionless.
If there is a child xsl:sequence
instruction whose
posture is not grounded, then
roaming and free-ranging.
Otherwise, the posture is grounded, and the sweep is the widest sweep of the
xsl:sequence
child instructions.
Note:
None of the branches of xsl:fork
can return streamed nodes.
The reason for this is that xsl:fork
has to assemble its
results in the correct order, and streamed nodes cannot be re-ordered.
The effect of the rules is that each of the child
xsl:sequence
instructions can independently consume the
streamed input document, provided that the result of each child instruction
is grounded.
Thus the following example is streamable:
<xsl:fork> <xsl:sequence select="copy-of(author)"/> <xsl:sequence select="copy-of(editor)"/> </xsl:fork>
While the following is not streamable, because it returns streamed nodes in an order that might not be document order:
<xsl:fork> <xsl:sequence select="author"/> <xsl:sequence select="editor"/> </xsl:fork>
xsl:if
The posture and sweep of
xsl:if
follow the general streamability rules. The operand roles and their usages are as follows:
The test
expression (usage inspection)
The contained sequence constructor (usage transmission).
xsl:iterate
The posture and sweep of the
xsl:iterate
instruction are the first of the following that
applies:
If the select
expression is grounded,
then the posture and sweep of the
xsl:iterate
instruction follow the general streamability rules, with the operand roles and their usages as follows:
The select
expression (the operand usage is irrelevant, but can be taken as
inspection)
The select
expression or contained sequence
constructor of any xsl:param
children (usage
navigation)
The sequence constructor contained within the
xsl:iterate
instruction itself, assessed with
its context item type and context posture based
on the select
expression (usage transmission)
The select
expression or contained sequence
constructor of any child xsl:on-completion
element, assessed with a context item type of xs:error
and a context posture of roaming to reflect the fact that any attempt to
reference the context item within the
xsl:on-completion
element is an error (usage
transmission)
Note:
The on-completion
element can cause the instruction to become non-streamable if,
for example, it contains a call on
current-group
or a variable reference
bound to a streaming parameter.
If there is an xsl:param
child whose initializing
select
expression or sequence constructor is not grounded
and motionless, then roaming and
free-ranging.
If there is an xsl:on-completion
child whose
select
expression or sequence constructor is not grounded
and motionless, then roaming and
free-ranging.
If the posture of the
select
expression is crawling and the
sweep of the contained sequence constructor is consuming, then
roaming and free-ranging.
Otherwise:
The posture of the instruction is the posture of the contained sequence constructor, assessed with the context posture
and context item type set to the posture and
type of the select
expression.
The sweep of the instruction is the wider of
the sweeps of the select
expression and the
contained sequence constructor,
where the ordering of increasing width is motionless, consuming, free-ranging.
Note:
If any xsl:break
or xsl:next-iteration
instructions appear within the sequence constructor, their posture and sweep will be assessed in the
course of evaluating the posture and sweep of the sequence constructor, by reference to the rules
in 19.8.4.8 Streamability of xsl:break and 19.8.4.28 Streamability of xsl:next-iteration respectively.
Note:
Because the body of the xsl:iterate
instruction is a
higher-order operand of the instruction, any variable
reference within the body that is bound to a streaming parameter of a containing stylesheet function will not be singular, which in many cases
will make the entire function non-streamable.
xsl:map
The posture and sweep of the xsl:map
instruction are determined
by the first of the following that applies:
If the sequence constructor within the instruction consists exclusively
of xsl:map-entry
instructions (and
xsl:fallback
instructions, which are ignored),
then:
If any of these xsl:map-entry
children is roaming or free-ranging, then
roaming and free-ranging;
Otherwise, grounded and the widest sweep of the
xsl:map-entry
children.
Otherwise, the posture and sweep
of the xsl:map
instruction are the posture and sweep of
the contained sequence constructor.
Note:
See discussion in 21.6 Maps and Streaming.
The effect of the rules is that it is possible to compute multiple map entries in a single pass of the streamed input document. For example, the following is streamable:
<xsl:map> <xsl:map-entry key="'authors'" select="copy-of(author)"/> <xsl:map-entry key="'editors'" select="copy-of(editor)"/> </xsl:map>
The call on copy-of
is necessary to ensure that the
content of the map entry is grounded; it is not possible to create a map
whose entries contain references to streamed nodes.
xsl:map-entry
The posture and sweep of
xsl:map-entry
follow the general streamability rules. The operand roles and their usages are as follows:
The key
expression (usage absorption)
The select
expression (usage navigation)
Note:
This effectively means that the select
expression must not return nodes from a streamed input document.
The contained sequence constructor (usage navigation).
xsl:merge
Note:
This section is concerned with the (not very interesting) impact of the
xsl:merge
instruction on the streamability of its
containing template rule or xsl:source-document
instruction.
For the (more important) rules concerning the way in which
xsl:merge
performs streamed processing of its own
inputs, see 15.4 Streamable Merging.
The posture and sweep of xsl:merge
are as follows:
If every xsl:merge-source
child element satisfies all
the following conditions:
The expression in the for-each-item
attribute is
either absent, or grounded and motionless;
The expression in the for-each-source
attribute is
either absent, or grounded and motionless;
Either at least one of the attributes for-each-item
and for-each-source
is present, or the expression in
the select
attribute is grounded
and motionless
then the xsl:merge
instruction is grounded and motionless.
Otherwise, the xsl:merge
instruction roaming and free-ranging.
xsl:message
The posture and sweep of
xsl:message
follow the general streamability rules. The operand roles and their usages are as follows:
The select
expression (usage absorption)
The terminate
attribute value template (usage absorption)
The error-code
attribute value template (usage absorption)
The contained sequence constructor (usage absorption).
xsl:namespace
The posture and sweep of
xsl:namespace
follow the general streamability rules. The operand roles and their usages are as follows:
The name
attribute value template (usage absorption)
The select
expression (usage absorption)
The contained sequence constructor (usage absorption).
xsl:next-iteration
The posture and sweep of
xsl:next-iteration
follow the general streamability rules. The operand roles and their usages are as follows:
The select
expression or sequence constructor content of any contained
xsl:with-param
child element: its operand usage is the type-determined usage based on the type declared in the
xsl:with-param/@as
attribute, or the
xsl:param/@as
attribute of the corresponding parameter on
the containing xsl:iterate
instruction, whichever is
more restrictive, defaulting to item()*
if both are
absent.
xsl:next-match
The rules are the same as for xsl:apply-imports
: see 19.8.4.4 Streamability of xsl:apply-imports.
xsl:number
The posture and sweep of
xsl:number
follow the general streamability rules. The operand roles and their usages are as follows:
The value
attribute if present: usage absorption
The select
attribute if there is
no value
attribute, defaulting to the context item
expression (.
) if the select
attribute is also
absent: usage navigation
The attribute value templates in the format
,
lang
, letter-value
, ordinal
,
start-at
, grouping-separator
, and
grouping-size
attributes (usage absorption)
The from
and count
patterns if present. These can be treated as higher-order operands with
usage inspection, though neither of these
properties affects the outcome.
Note:
The effect of these rules is that xsl:number
can be used
for formatting of numbers supplied directly using the value
attribute, and also for numbering of nodes in a non-streamed document, but
it cannot be used for numbering streamed nodes.
In practice the rules depend very little on the from
and
count
patterns. This is because when the instruction is
applied to a streamed node, the instruction will be free-ranging regardless of these patterns; while if it is
applied to a grounded node or atomic value, the instruction will normally be
motionless regardless of the values of these
patterns. The pattern does matter,
however, if it contains a variable reference bound to a streaming parameter;
because such a reference occurs within a higher-order operand of the xsl:number
instruction, its presence automatically makes the variable reference
free-ranging, which in turn ensures that the
containing stylesheet function is not guaranteed-streamable.
xsl:on-empty
The streamability rules for the xsl:on-empty
instruction are
the same as the rules for xsl:sequence
: see 19.8.4.36 Streamability of xsl:sequence.
Note:
The streamability rules for a sequence constructor containing an
xsl:on-empty
instruction are given in 19.8.3 Classifying Sequence Constructors.
xsl:on-non-empty
The streamability rules for the xsl:on-non-empty
instruction
are the same as the rules for xsl:sequence
: see 19.8.4.36 Streamability of xsl:sequence.
Note:
The streamability rules for a sequence constructor containing an
xsl:on-non-empty
instruction are given in 19.8.3 Classifying Sequence Constructors.
xsl:perform-sort
The posture and sweep of
xsl:perform-sort
follow the general streamability rules. The operand roles and their usages are as follows:
The expression in the select
attribute: usage navigation (because order is not preserved)
The expressions in the attribute value templates of
xsl:sort
child elements: usage absorption
The expression in the select
attribute or contained sequence constructor in child
xsl:sort
child elements, with usage absorption, assessed with context posture based on the
expression in the xsl:perform-sort/@select
attribute.
Note:
In practice, the xsl:perform-sort
instruction cannot be
used to sort nodes from the streamed input document, but it can be used to
sort atomic values or grounded nodes, for example a copy
of nodes from the streamed document made using the
copy-of
function.
xsl:processing-instruction
The posture and sweep of
xsl:processing-instruction
follow the general streamability rules. The operand roles and their usages are as follows:
The name
attribute value template (usage absorption)
The select
expression (usage absorption)
The contained sequence constructor (usage absorption).
xsl:result-document
The posture and sweep of
xsl:result-document
follow the general streamability rules. The operand roles and their usages are as follows:
The href
attribute value template (usage absorption)
The attribute value templates containing serialization properties (usage absorption)
The contained sequence constructor (usage absorption).
xsl:sequence
The posture and sweep of
xsl:sequence
follow the general streamability rules. The operand roles and their usages are as follows:
The select
attribute value template (usage transmission)
The contained sequence constructor (usage transmission).
xsl:source-document
Note:
The concern here is with the impact of xsl:source-document
on any
streaming template, or ancestor xsl:source-document
instruction, and
not with the streamed processing of the document accessed using the
xsl:source-document/@href
attribute.
The streamability of the document opened by the xsl:source-document
instruction is not assessed using the rules in this section; it depends only
on the streamability properties of the contained sequence constructor, as
described in 18.1 The xsl:source-document Instruction
The posture and sweep of
xsl:source-document
are the first of the following that applies:
If the contained sequence constructor contains, at any depth, a call on the
current-group
function whose nearest
containing xsl:for-each-group
instruction
exists and is an ancestor of the xsl:source-document
instruction,
then roaming and free-ranging.
If the contained sequence constructor contains, at any depth, a call on the
current-merge-group
function whose nearest
containing xsl:merge
instruction exists and
is an ancestor of the xsl:source-document
instruction, then
roaming and free-ranging.
Otherwise, the posture is grounded and the sweep is the sweep of
the href
attribute value template.
xsl:text
The posture and sweep of
xsl:text
follow the general streamability rules. There are no operands.
Note:
The instruction is therefore grounded and motionless.
xsl:try
The posture and sweep of the xsl:try
instruction
follow the general streamability rules. The operand roles and usages are as follows:
The select
expression or contained sequence constructor of the xsl:try
element. This has operand usage
transmission. (Note that the
xsl:catch
children of xsl:try
are
not part of the sequence constructor and therefore not part of this
operand.)
The select
expressions and/or contained sequence constructor of the xsl:catch
child elements. These form a choice operand group
with operand usage
transmission.
xsl:value-of
The posture and sweep of
xsl:value-of
follow the general streamability rules. The operand roles and their usages are as follows:
The select
expression (usage absorption)
The separator
attribute value template (usage absorption)
The contained sequence constructor (usage absorption).
xsl:variable
The posture and sweep of
xsl:variable
follow the general streamability rules. The operand roles and their usages
depend on the as
attribute,
as follows:
If there is an as
attribute, then:
The select
expression (with type-determined usage based on the as
attribute).
The contained sequence constructor (with
type-determined usage based on the
as
attribute).
If there is no as
attribute,
then:
The select
expression (usage navigation).
The contained sequence constructor (usage absorption).
Note:
The effect of the initialization expression having usage navigation is that it is not possible in streamable constructs to bind a variable to a node in a streamed document.
xsl:where-populated
The posture and sweep of an
xsl:where-populated
instruction are the posture and sweep of the contained sequence constructor.
Under specific conditions, described in this section, a stylesheet function can be used to process nodes from a streamed input document.
[Definition: Stylesheet functions belong to one of a number of streamability categories: the choice of category characterizes the way in which the function handles streamed input.]
The category to which a
function belongs is declared in the streamability
attribute of the
xsl:function
declaration, and defaults to
unclassified
.
The streamability categories defined in this specification are:
unclassified
, absorbing
, inspection
,
filter
, shallow-descent
, deep-descent
,
and ascent
. It is also possible to specify the streamability category
as a QName in an implementation-defined namespace, in which
case the streamability rules are implementation-defined; a
processor that does not recognize a category defined in this way
must analyze the function as if
streamability="unclassified"
were specified.
A stylesheet function is declared-streamable if the
xsl:function
declaration has a streamability
attribute with a value other than unclassified
.
The only category permitted for
a zero-arity function (one with no arguments) is unclassified
. All
function calls to zero-arity stylesheet functions are grounded
and motionless.
In general (subject to more detailed rules below), a node belonging to a streamed document can be present within the value of an argument of a call on a stylesheet function only if one of the following conditions is true:
The stylesheet function is declared-streamable, and the argument in question is the first argument of the function call.
The corresponding function parameter is declared with a required type that triggers atomization of any supplied node.
[Definition: The first parameter of a declared-streamable stylesheet function is referred to as a streaming parameter.]
Note:
If a stylesheet function returns streamed nodes, then these nodes can only
derive from streamed nodes passed in an argument to the function. This is
because streamed nodes cannot be bound to global variables, and they cannot be
returned by an xsl:source-document
instruction within the function body
(the result of xsl:source-document
is always grounded).
The choice of category places constraints on the function body, and also on calls to the function. These constraints are defined below, separately for each category. A function is guaranteed-streamable only if the constraints are satisfied, and a static function call is guaranteed-streamable only if the function is guaranteed-streamable and the function call itself satisfies the constraints for the chosen category.
Dynamic function calls are guaranteed-streamable only in trivial cases, for example where the function signature indicates that an argument is required to be a text node or an attribute node. For details, see 19.8.8.11 Streamability of Dynamic Function Calls.
The constraints on the function body are expressed in terms of the posture and sweep of the function result. The
posture and sweep of the function
result are the type-adjusted posture and sweep of the sequence constructor contained within the
xsl:function
element, given the declared return type of the
function, which defaults to item()*
.
Note:
Determining the posture and sweep of the function result requires first determining the posture and sweep of the contained sequence constructor, which is done according to the rules in 19.8.3 Classifying Sequence Constructors. This in turn will usually involve examination of variable references that are bound to the function’s parameters. The analysis of these variable references is described in 19.8.8.12 Streamability of Variable References.
If the function is declared-streamable but does not satisfy the constraints that make it guaranteed-streamable, the consequences are explained in 19.10 Streamability Guarantees.
If a stylesheet function is overridden in another package (using
xsl:override
), then the overriding stylesheet function must
belong to the same streamability category as the function that
it overrides. This ensures that overriding a function cannot affect the
streamability of calls to that function.
The rules for each streamability category are given in the following sections.
Informal description: Functions in this category cannot be called with streamed nodes supplied in an argument, unless the function signature causes such nodes to be atomized.
Rules for the function signature: there are no constraints.
Rules for the function body: there are no constraints.
Rules for references to the streaming parameter: not applicable, because there is no streaming parameter.
Rules for function calls: the general streamability rules apply. The operands are the expressions appearing in the argument list of the function call, with the operand usage of each operand being the type-determined usage based on the declared type of the corresponding parameter in the function signature.
The streamability category is
unclassified
.
<xsl:function name="f:exclude-first" as="node()*"> <xsl:param name="nodes" as="node()*"/> <xsl:sequence select="$nodes[not(node-name() = preceding-sibling::*/node-name())]"/> </xsl:function>
The effect of the rules is that a call to this function is guaranteed
streamable if and only if the sequence supplied as the value of the
$nodes
argument is grounded (that is, it
contains no streamed nodes).
The streamability category is
unclassified
.
<xsl:function name="f:min" as="xs:integer"> <xsl:param name="arg0" as="xs:integer"/> <xsl:param name="arg1" as="xs:integer"/> <xsl:sequence select="min(($arg0, $arg1))"/> </xsl:function>
The effect of the rules is that a call to this function is streamable under
similar circumstances to those that apply to a binary operator such as
+
. For example, a call is streamable if two atomic values
are supplied, or if two attribute nodes are supplied, whether from streamed
or unstreamed documents. The main constraint is that it is not permitted for
both arguments to be consuming; for example, if the context node is a node
in a streamed document, then the function call f:min((price,
discount))
would not be guaranteed streamable.
Informal description: Functions in this category typically read the subtrees rooted at the node or nodes supplied in the first argument. These subtrees must not overlap each other. The function must not return any streamed nodes.
Rules for the function signature: there are no constraints.
Rules for the function body: For the function to be guaranteed-streamable, the type-adjusted posture of the function body with respect to the declared return type must be grounded, and the type-adjusted sweep of the function body with respect to the declared return type must be motionless or consuming.
Rules for references to the streaming parameter: If the declared type of the streaming parameter permits more than one node, then a variable reference referring to the streaming parameter is striding and consuming. Otherwise such a variable reference is striding and motionless.
Rules for function calls: If the first argument is crawling then the function call is roaming and free-ranging; otherwise the general streamability rules apply. The operands are the expressions appearing in the argument list of the function call. The operand usage of the first argument is absorption; the operand usage of other arguments is the type-determined usage based on the declared type of the corresponding parameter in the function signature.
Note:
Absorbing functions perform an operation analogous to atomization on their supplied arguments, in that they typically use information from the subtree rooted at a node to compute atomic values. Atomization can be seen as a special case of absorption. Calls on absorbing functions are therefore, from a streamability point of view, equivalent to calls on functions that implicitly atomize the supplied nodes.
An important difference, however, is that whereas atomization can be applied to any argument of a function call, absorption applies only to the first argument.
Another difference is that atomization is allowed on a sequence of nodes in
crawling posture, whereas generalized absorption is
not. Within a sequence, there may be nodes whose subtrees overlap, and the
code for atomization is expected to handle this, but more general absorption
operations are not. To write a function that accepts streamed nodes and
atomizes them, it is better to use the streamability category
unclassified
, and to declare the first argument with an
atomic type, rather than using the category absorbing
which
allows more general processing, but restricts what can be supplied in the
argument to the function call.
The following function is declared as absorbing, and the function body meets the rules for this category because it makes downward selections only, and returns an atomic value.
<xsl:function name="f:count-descendants" as="xs:integer" streamability="absorbing"> <xsl:param name="input" as="node()*"/> <xsl:sequence select="count($input//*)"/> </xsl:function>
The effect of the rules is that a call to this function is guaranteed-streamable provided that the sequence supplied as
the value of the $nodes
argument is motionless or consuming, and is either
grounded or striding.
The following function is declared as absorbing, and the function body meets the rules for this category because it makes downward selections only from the node supplied as the first argument, and returns an atomic value.
<xsl:function name="f:compare-size" as="xs:integer" streamability="absorbing"> <xsl:param name="input0" as="node()"/> <xsl:param name="input1" as="node()"/> <xsl:sequence select="count($input0//*) - count($input1//*)"/> </xsl:function>
This function takes two nodes as its arguments. Some examples of function calls include:
Streamable: f:compare-size(a, b)
where a
is
an element in a streamed document and b
is an element in
an unstreamed document
Streamable: f:compare-size(a, b)
where a
and
b
are both elements in unstreamed documents
Not streamable: f:compare-size(a, b)
where a
is an element in an unstreamed document and b
is an
element in a streamed document
The reason for the asymmetry is that for the first argument the operand usage is absorption, while for the second argument it is navigation. It is a consequence of the general streamability rules that when streamed nodes are supplied to an operand with usage navigation, the resulting expression is roaming and free-ranging.
The following function is declared as absorbing, and the function body meets
the rules for this category. Analysis of the function body reveals that it
is grounded and consuming; to establish this, it is necessary to analyze the
recursive call f:outline(*)
, and this is possible because it is
known to be a call on an absorbing stylesheet function.
<xsl:function name="f:outline" as="xs:string" streamability="absorbing"> <xsl:param name="input" as="element()*"/> <xsl:value-of select="$input ! (name() || '(' || f:outline(*) || ')')" separator=", "/> </xsl:function>
The effect of the rules is that a call to this function is guaranteed
streamable in the typical case where the sequence supplied as the value of
the $input
argument is striding and
consuming.
Informal description: Functions in this category typically return properties of the node supplied in the first argument, where these properties can be determined without advancing the input stream. This allows access to properties such as the name and type of each node, and also to its ancestors, attributes, and namespaces.
Rules for the function signature: If the declared type of the streaming parameter permits more than one node, the function is not guaranteed-streamable.
Rules for the function body: For the function to be guaranteed-streamable, the type-adjusted posture of the function body with respect to the declared return type must be grounded, and the type-adjusted sweep of the function body with respect to the declared return type must be motionless.
Rules for references to the streaming parameter: Such a variable reference is striding and motionless.
Rules for function calls: the general streamability rules apply. The operands are the expressions appearing in the argument list of the function call. The operand usage of the first argument is inspection; the operand usage of other arguments is the type-determined usage based on the declared type of the corresponding argument in the function signature.
Note:
The streaming parameter is restricted to be a single
node because if $input
were a sequence of nodes, then an
expression such as ($input/name(), $input/@id)
would not be
streamable.
The following function is declared with category inspection
,
and the function body meets the rules for this category because all
references to the supplied node are motionless.
<xsl:function name="f:depth" as="xs:integer" streamability="inspection"> <xsl:param name="input" as="node()"/> <xsl:sequence select="count($input/ancestor-or-self::*)"/> </xsl:function>
The effect of the rules is that a call to this function is guaranteed
streamable provided that the expression supplied as the value of the
$nodes
argument is motionless or
consuming.
The following function is declared with category inspection
,
and the function body meets the rules for this category because the function
signature ensures that the second argument cannot be a node.
<xsl:function name="f:get-attribute-value" as="xs:string"> <xsl:param name="element" as="node()"/> <xsl:param name="attribute-name" as="xs:string"/> <xsl:sequence select="string($element/@*[local-name() = $attribute-name])"/> </xsl:function>
Although the normal usage of this function might be to supply an element from a streamed document as the first argument, and a literal string as the second, it is also permissible (and guaranteed streamable) to supply an unstreamed element as the first argument, and an element node from a streamed document as the second. When applying the general streamability rules in this case, the first operand is grounded and motionless, while the second is grounded and consuming (by virtue of the rules for type-determined usage), and this makes the function call grounded and consuming.
Informal description: Functions in this category typically return either the node supplied in the first argument or nothing, depending on the values of properties that can be determined without advancing the input stream. This allows access to properties such as the name and type of each node, and also to its ancestors, attributes, and namespaces.
Rules for the function signature: If the declared type of the streaming parameter permits more than one node, the function is not guaranteed-streamable.
Rules for the function body: For the function to be guaranteed-streamable, the type-adjusted posture of the function body with respect to the declared return type must be striding, and the type-adjusted sweep of the function body with respect to the declared return type must be motionless.
Rules for references to the streaming parameter: Such a variable reference is striding and motionless.
Rules for function calls: The posture and sweep of a call to a function in this category are determined by applying the general streamability rules. The operands are the expressions supplied as arguments to the function call. The first argument has operand usage transmission; any further arguments have type-determined usage based on the declared type of the corresponding parameter in the function signature.
The following function is declared as filtering, and the function body meets the rules for this category because it selects nodes from the input based on motionless properties (namely, the existence of attributes).
<xsl:function name="f:large-regions" as="element(region)" streamability="filter"> <xsl:param name="input" as="element(region)"/> <xsl:sequence select="$input[@size gt 1000]"/> </xsl:function>
The effect of the rules is that the posture and sweep of a function call
f:large-regions(EXPR)
are the same as the posture and sweep of EXPR
.
Although the name filter
suggests that the result must always
be a subset of the input, this is not strictly required by the rules. The
function can also return atomic values, as well as attribute and namespace
nodes.
Informal description: Functions in this category typically return children of the nodes supplied in the first argument. They may also select deeper in the subtrees of these nodes, provided that no node in the result can possibly be an ancestor of any other node in the result.
Rules for the function signature: If the declared type of the streaming parameter permits more than one node, the function is not guaranteed-streamable.
Rules for the function body: For the function to be guaranteed-streamable, the type-adjusted posture of the function body with respect to the declared return type must be striding, and the type-adjusted sweep of the function body with respect to the declared return type must be motionless or consuming.
Rules for references to the streaming parameter: Such a variable reference is striding and motionless.
Rules for function calls: The rules are as follows, in order:
Let T0 be the U-type corresponding to the declared type of the streaming parameter in the function signature (defaulting to U{*}).
Let P0 and S0 be the type-adjusted posture and sweep of the first argument expression, based on type T0.
If P0 is not striding or grounded, the function call is roaming and free-ranging.
Consider a construct C whose operands are the argument expressions other than the first argument, with type-determined operand usage based on the declared type of the corresponding parameter in the function signature. Let P1 and S1 be the posture and sweep of C, assessed using the general streamability rules.
Note:
If there is only one argument, then P1 is grounded and S1 is motionless.
If P1 is not grounded, the function call is roaming and free-ranging.
If S0 and S1 are both consuming, or if either is free-ranging, then the function call is roaming and free-ranging.
If P0 is grounded, then the posture of the function call is grounded, and the sweep of the function call is the wider of S0 and S1.
Otherwise, the posture of the function call is P0, and the sweep of the function call is as follows:
If the intersection of T0 with U{document-node(), element()} is empty (that is, the declared type of the first argument does not permit document or element nodes) then S0.
Let A be the static type of the expression supplied as the first argument. If the intersection of A with U{document-node(), element()} is empty (that is, the inferred type of the expression supplied as the first argument does not permit document or element nodes) then S0.
Otherwise, consuming.
The following function is declared as shallow-descent, and the function body meets the rules for this category because it selects children of the supplied input node.
<xsl:function name="f:alternate-children" as="node()*" streamability="shallow-descent"> <xsl:param name="input" as="element()"/> <xsl:sequence select="$input/node()[position() mod 2 = 1]"/> </xsl:function>
The effect of the rules is that a call to this function is guaranteed
streamable in the typical case where the node supplied as the value of
the $input
argument is striding and
consuming.
Informal description: Functions in this category typically return descendants of the nodes supplied in the first argument.
Rules for the function signature: If the declared type of the streaming parameter permits more than one node, the function is not guaranteed-streamable.
Rules for the function body: For the function to be guaranteed-streamable, the type-adjusted posture of the function body with respect to the declared return type must be crawling, and the type-adjusted sweep of the function body with respect to the declared return type must be motionless or consuming.
Rules for references to the streaming parameter: Such a variable reference is striding and motionless.
Rules for function calls: The rules are as follows, in order:
Let T0 be the U-type corresponding to the declared type of the streaming parameter in the function signature (defaulting to U{*}).
Let P0 and S0 be the type-adjusted posture and sweep of the first argument expression, based on type T0.
If P0 is not striding or grounded, the function call is roaming and free-ranging.
Consider a construct C whose operands are the argument expressions other than the first argument, with type-determined operand usage based on the declared type of the corresponding parameter in the function signature. Let P1 and S1 be the posture and sweep of C, assessed using the general streamability rules
Note:
If there is only one argument, then P1 is grounded and S1 is motionless.
If P1 is not grounded, the function call is roaming and free-ranging.
If S0 and S1 are both consuming, or if either is free-ranging, the function call is roaming and free-ranging.
If P0 is grounded, then the posture of the function call is grounded, and the sweep of the function call is the wider of S0 and S1.
Otherwise, the posture of the function call is crawling, and the sweep of the function call is as follows:
If the intersection of T0 with U{document-node(), element()} is empty (that is, the declared type of the first argument does not permit document or element nodes) then S0.
Let A be the static type of the expression supplied as the first argument. If the intersection of A with U{document-node(), element()} is empty (that is, the inferred type of the expression supplied as the first argument does not permit document or element nodes) then S0.
Otherwise, consuming.
The following function is declared as deep-descent, and the function body meets the rules for this category because it selects descendants of the supplied input node.
<xsl:function name="f:all-comments" as="comment()*" streamability="deep-descent"> <xsl:param name="input" as="element()"/> <xsl:sequence select="$input//comment()"/> </xsl:function>
The effect of the rules is that a call to this function is guaranteed
streamable in the typical case where the node supplied as the value of
the $input
argument is striding and
consuming.
Informal description: Functions in this category typically return ancestors of the nodes supplied in the first argument.
Rules for the function signature: If the declared type of the streaming parameter permits more than one node, the function is not guaranteed-streamable.
Rules for the function body: For the function to be guaranteed-streamable, the type-adjusted posture of the function body with respect to the declared return type must be either climbing or grounded, and the type-adjusted sweep of the function body with respect to the declared return type must be motionless.
Rules for references to the streaming parameter: Such a variable reference is climbing and motionless.
Rules for function calls: The posture and sweep of a call to a function in this category are determined as follows:
Let P0 and S0 be the posture and sweep obtained by assessing the function call using the general streamability rules, where the operands are the arguments to the function call, with an operand usage for the first argument of inspection, and an operand usage for arguments after the first being the type-determined usage based on the declared type of the corresponding function parameter.
If P0 is roaming or S0 is free-ranging, then the function call is roaming and free-ranging.
If S0 is not motionless, then the function call is roaming and free-ranging.
If P0 is roaming, then the function call is roaming and free-ranging.
If P0 is grounded, then the function call is grounded and motionless.
Otherwise, the function call is climbing and motionless.
The following function is declared with category ascent
, and
the function body meets the rules for this category because it selects
ancestors of the supplied node.
<xsl:function name="f:containing-section" as="element(section)" streamability="ascent"> <xsl:param name="input" as="element(para)*"/> <xsl:sequence select="$input/ancestor::section[last()]"/> </xsl:function>
The effect of the rules is that a call to this function is guaranteed
streamable provided that the node supplied as the value of the
input
argument is not roaming or
free-ranging. There are no other constraints on the
node supplied in the input sequence.
The posture of an attribute set is always grounded (its result can never return streamed nodes).
The sweep of an attribute set is motionless if all the following conditions hold:
Every xsl:attribute
instruction within the declarations comprising the attribute set
is motionless when assessed as described in 10.2.3 Streamability of Attribute Sets,
using a context posture of striding.
Every attribute set referenced in the use-attribute-sets
attribute of an xsl:attribute-set
declaration of the attribute set has the attribute streamable="yes"
.
If the sweep of an attribute set is not motionless then it is free-ranging.
Note:
Attribute sets will always be grounded, because they return newly constructed attribute nodes.
Attribute sets will very often be motionless, but if they access the context item, they may be free-ranging. Although some attribute sets could theoretically be classified as consuming, this option has been excluded because it is unlikely to be useful; given the requirement to create attributes whose values are obtained by reading a streamed input document, use of a streamable template rule is a more versatile approach.
Because attribute sets can be overridden in another package, the streamability of a construct such as an
xsl:element
instruction containing a
use-attribute-sets
attribute is based on the declared
streamability of the named attribute sets, as defined by the
streamable
attribute of the xsl:attribute-set
element. If streamable="yes"
is specified, then there is a
requirement that any overriding attribute set should also specify
streamable="yes"
, and a streaming processor is required to
check that an attribute set containing such a declaration does in fact satisfy
the streamability rules.
A value template (that is, an attribute value template or text value template)
is a construct whose operands are the expressions contained
within curly brackets. The required type for this operand role is
xs:string
and the usage
is absorption.
The sweep and posture of a value template are determined using the general rules in 19.8.1 General Rules for Streamability.
If there are no expressions contained within curly brackets, the value template is motionless.
XPath expressions are classified using the rules in this section.
In the analysis that follows, expressions are classified according to the most specific production rule that they match for which there is an entry in this section. A production P is considered more specific than a production Q (Q ≠ P) if every expression that matches P also matches Q. For example:
The expression 3
satisfies the productions
NumericLiteral
, Literal
, and
ArithmeticExpression
; the most specific of these for which
there is an entry in this section is Literal
.
The expression text()
(appearing as an expression) is a
TextTest
, and therefore a KindTest
, which is
itself a NodeTest
, and therefore an AxisStep
with
a defaulted ForwardAxis
. The most specific of these for which
there is an entry in this section is AxisStep
. Although the
expression is also a RelativePathExpr
, that production is less
specific than AxisStep
so its rules do not apply.
The expression section/title
is a
RelativePathExpr
, for which there is an entry in this section.
Although the expression is also a PathExpr
, that production is
less specific than RelativePathExpr
so its rules do not
apply.
The production rules for different kinds of expression are listed (with their names and numbers) in the order in which they appear in Appendix A.1 of the XPath 3.0 specification; rules are also given for new constructs introduced by XPath 3.1. Where two numbers are given, they are the production rule numbers in XPath 3.0 and XPath 3.1 respectively; where there is a single number, it is the production rule number in XPath 3.1.
Many expressions can be analyzed using the general streamability rules. These are indicated in the table below
by means of a simple proforma in which the operand
roles are represented by a short code (A = absorption, I = inspection, T = transmission, N = navigation). For example the
proforma A + A
indicates that for an arithmetic expression, both
operands have operand usage
absorption, while I or I
indicates that for an
or
expression, both operands have operand usage
inspection. For expressions where further explanation is
needed, the table contains a link to the relevant section.
Construct | Proforma or Reference to Detailed Rules | Further Information |
---|---|---|
Expr [6,6] | T, T |
|
ForExpr [8,8] | See 19.8.8.1 Streamability of for Expressions | |
LetExpr [11,11] | let $var := N return T |
Binding of variables to streamed nodes is not allowed. |
QuantifiedExpr [14,14] | See 19.8.8.2 Streamability of Quantified Expressions | |
IfExpr [15,15] | if (I) then T else
T |
The then-clause and else-clause form a choice operand group with usage transmission |
OrExpr [16,16] | I or I |
|
AndExpr [17,17] | I and I |
|
StringConcatExpr [19,19] | A || A |
|
RangeExpr [20,20] | A to A |
|
AdditiveExpr [21,21] | A + A , A - A |
|
MultiplicativeExpr [22,22] | A * A , A div A , etc.
|
|
UnionExpr [23,23] | See 19.8.8.4 Streamability of union, intersect, and except Expressions | |
IntersectExceptExpr [24,24] | See 19.8.8.4 Streamability of union, intersect, and except Expressions | |
InstanceOfExpr [25,25] | See 19.8.8.5 Streamability of instance of Expressions | |
TreatExpr [26,26] | See 19.8.8.6 Streamability of treat as Expressions | |
CastableExpr [27,27] | A castable as TYPE |
|
CastExpr [28,28] | A cast as TYPE |
|
UnaryExpr [29,30] | +A , -A |
|
GeneralComp [31,32] | A = A , A < A , A != A ,
etc.
|
|
ValueComp [32,33] | A eq A , A lt A , A ne A , etc.
|
|
NodeComp [33,34] | I is I , I <<
I , I >> I |
See Note 1 below |
SimpleMapExpr [34,35] | See 19.8.8.7 Streamability of Simple Mapping Expressions | |
PathExpr [35,36] | See 19.8.8.8 Streamability of Path Expressions | |
RelativePathExpr [36,37] | See 19.8.8.8 Streamability of Path Expressions | |
AxisStep [38,39] | See 19.8.8.9 Streamability of Axis Steps | |
ForwardStep [39,40], ReverseStep [42,43] | See 19.8.8.9 Streamability of Axis Steps | |
PostfixExpr [48,49]: Filter Expression | See 19.8.8.10 Streamability of Filter Expressions | |
PostfixExpr [48,49]: Dynamic Function Call | See 19.8.8.11 Streamability of Dynamic Function Calls | |
Literal [53,57] | There are no operands, so the construct is grounded and motionless | |
VarRef [55,59] | See 19.8.8.12 Streamability of Variable References | |
ParenthesizedExpr [57,61] | (T) |
|
() |
There are no operands, so the construct is grounded and motionless | |
ContextItemExpr [58,62] | See 19.8.8.13 Streamability of the Context Item Expression | |
FunctionCall [59,63] | See 19.8.8.14 Streamability of Static Function Calls | |
NamedFunctionRef [63,67] | See 19.8.8.15 Streamability of Named Function References | |
InlineFunctionExpr [64,68] | See 19.8.8.16 Streamability of Inline Function Declarations | |
MapConstructor [–,69] | See 19.8.8.17 Streamability of Map Constructors | |
Lookup (Postfix [–,49] and Unary [–,53]) | See 19.8.8.18 Streamability of Lookup Expressions | |
ArrowExpr [–,29] | See 19.8.8.14 Streamability of Static Function Calls
and 19.8.8.11 Streamability of Dynamic Function Calls:
the rules for X => F(Y, Z) are the same as the rules for F(X, Y, Z) |
|
SquareArrayConstructor [–,74] | [N, N, ...] |
|
CurlyArrayConstructor [–,75] | array{N, N, ...} |
Note:
The operators is
, <<
, and
>>
apply to streamed nodes just as to any other
nodes, though there are few practical situations where they will be
useful. A streamed document conforms to the rules of the XDM data model,
and its nodes are therefore distinct and ordered. They follow the usual
rules, for example that a parent node precedes its children in document
order. Expressions such as .. is parent::X
or
ancestor::x[1] << ancestor::y[1]
are therefore
perfectly meaningful. The usefulness of the operators is limited by the
fact that variables cannot be bound to nodes in a streamed document. It
is permitted, though perhaps not useful, for one of the operands to be
consuming: one can write . <<
child::x
, and the resulting expression is (by applying the
general rules) consuming and grounded.
The restriction that variables cannot be bound to streamed nodes prevents
writing of expressions such as let $x := . return
descendant::x[ancestor::y[1] is $x]
. As a workaround, the
intended effect can be achieved by comparing node identity using the
generate-id
FO30 function: let $x :=
generate-id(.) return descendant::x[generate-id(ancestor::y[1]) =
$x]
for
ExpressionsWriting the expression as for $v in S return R
, the two operand
roles are S and R.
The posture and sweep are determined by the first of the following that applies:
If S is not grounded, then roaming and free-ranging.
Otherwise, the general streamability rules apply. The operand roles are:
The in
expression (S
). This has usage
navigation.
The return
expression (R
). This is a
higher-order operand with usage
transmission.
Note:
Expressions of the form for $i in 1 to 3 return $i*2
, where
there is no reference to a streamed node, are clearly streamable.
The in
expression can also be consuming,
for example for $e in copy-of(emp) return $e/salary
.
The rule that S must be grounded
prevents the variable being bound to a node in a streamed document. This
disallows expressions of the form for $x in child::section return
$x/para
, because this requires data flow analysis (tracing from
the binding of a variable to its usages), rather than purely syntactic
analysis. Some implementations may be able to stream such constructs.
The fact that the return clause is a higher-order operand prevents it from
being a consuming expression, for example for $i
in 1 to 3 return salary
. Use of a motionless expression that
accesses streamed nodes is however allowed, for example for $i in 1 to
3 return name(ancestor::x[$i])
.
An expression with multiple in-clauses is first rewritten using nested
quantified expressions: for example some $i in X, $j in Y satisfies $i eq
$j
can be rewritten as some $i in X satisfies (some $j in Y
satisfies $i eq $j)
. The analysis therefore only needs to consider
expressions with a single in-clause.
Writing such an expression as some|every $v in S satisfies C
, the
two operand roles are S and C.
The general streamability rules apply. The operand roles are:
The in
expression (S). This has usage navigation.
The satisfies
expression (C). This is a higher-order operand with usage inspection.
Note:
Expressions of the form some $i in 1 to 3 satisfies $i lt 2
,
where there is no reference to a streamed node, are clearly streamable.
The expression S can be consuming, so long as
it is grounded: for example some $e in emp/salary/number(.) satisfies
$e gt 10000
.
The rule that S has usage navigation prevents
the variable being bound to a node in a streamed document. This disallows
expressions of the form some $x in child::section satisfies
has-children($x)
, because this requires data flow analysis
(tracing from the binding of a variable to its usages), rather than purely
syntactic analysis. Some implementations may be able to stream such
constructs.
The fact that C is a higher-order operand prevents it from being
a consuming expression: for example some $i in 1
to 3 satisfies author[$i] eq "Kay"
is not streamable. Use of a
motionless expression that accesses streamed nodes is however allowed, for
example some $i in 1 to 3 satisfies @grade = $i
.
Quantified expressions that fail the streamability rules can often be
rewritten as filter expressions. For example, the expression some $x in
child::section satisfies has-children($x)
can be rewritten as
exists(child::section[has-children(.)])
, which is grounded
and consuming.
if
expressionsWriting the expression as if (C) then T else E
, there are three
operand roles: C, T, and E. The usage of C is inspection, while the usage of T and E is transmission. Operands T and E form a
choice operand group, meaning that they can both consume
the input stream, provided they have consistent posture.
The general streamability rules apply.
union
, intersect
, and
except
ExpressionsThe posture and sweep are the first of the following that applies:
If either of the two operands is free-ranging, then
roaming and free-ranging
(Example: . | following-sibling::*
).
If either of the two operands is grounded and
motionless, then the posture
and sweep of the other operand (Example: . |
doc('abc.com')//x
)
If both operands are climbing, then climbing and and the
wider of the sweeps of the two operands (Example: parent::A | */ancestor::B
).
If the left-hand operand is striding or crawling and the right-hand operand is also
striding or crawling, then crawling and the wider of the
sweeps of the two operands (Example: * | */*
).
Otherwise, roaming and free-ranging (Example: child::div |
parent::div
).
Note:
Essentially the principle is that if both operands are streamable, then the
result is streamable (this assumes an evaluation strategy where both
operands are evaluated during the same pass of the streamed input document,
and the results merged). But there are caveats because of the need for
static streamability analysis of the result. This prevents constructs such
as .. | *
that have heterogeneous posture.
Where the two operands are both striding, there are
cases where an implementation could determine that the result is also
striding: for example (author | editor)
.
In general, however, the combination of two striding operands may produce a
sequence of nodes that have nested subtrees (consider author | author/name
),
so the result is classified as crawling.
The expression (author | editor)
, although it is not striding, can be rewritten in the form *[self::author or
self::editor]
, which is striding.
instance of
ExpressionsFor an expression of the form X instance of ST (where X is an expression and ST is a SequenceType), the posture and sweep are determined by the general streamability rules. There is a single operand X, whose operand usage is as follows:
If the ItemType
of ST is a
DocumentTest
, optionally parenthesized, that contains an
ElementTest
or SchemaElementTest
then
absorption
Otherwise, inspection.
Note:
In general, it is possible to determine whether a node matches an
ItemType
without consuming the node. For example it can be
established whether an element matches the test element(para)
when positioned at the start tag.
An ItemType
of the form document-node(element(X))
is a exception to this rule because it matches a document node only if it
has exactly one element node child, and this cannot be determined without
consuming the document.
A processor may have knowledge that the document node cannot contain multiple element nodes, for example because it knows that the source of the streamed document is an XML parser that is not capable of generating such a stream. In such cases the processor may make a different assessment of the streamability of this construct. This comes under the general provision that a processor is always at liberty to use streaming even when the stylesheet is not guaranteed streamable.
Note:
As with other constructs that are evaluated with inspection usage, for
example the name
FO30 function or access to an attribute
node, evaluation of a construct such as $X instance of
schema-element(E)
as true or false may be invalidated if reading
of the input stream subsequently fails. Dynamic errors during streamed
processing of an input document invalidate all output generated prior to the
failure, and this case is no different.
Note:
Given an expression such as child::* instance of element(E)*
,
the expression as a whole is consuming and grounded. By
contrast, the expression . instance of element(E)*
is
motionless and grounded. This can be verified by applying the general
streamability rules to these cases.
treat as
ExpressionsFor an expression of the form X treat as ST (where X is an expression and ST is a SequenceType), the posture and sweep are determined as follows:
If the ItemType
of ST is a
DocumentTest
, optionally parenthesized, that contains an
ElementTest
or SchemaElementTest
then
roaming and free-ranging.
Otherwise, the general streamability rules apply. There is a single operand X, whose operand usage is transmission.
Note:
See the notes in 19.8.8.5 Streamability of instance of Expressions for
a discussion of the streamability difficulties associated with document-node()
tests.
The mapping operator !
is treated as a left-associative binary
operator, so the expression a!b!c
is processed as
(a!b)!c
.
The posture of the expression is the posture of the right-hand operand, assessed with a context posture and type set to the posture and type of the left-hand operand.
The sweep of the expression is the wider of the sweeps of the two operands.
The streamability analysis applies after the expansion of the //
pseudo-operator to /descendant-or-self::node()/
, and after
expanding ..
to parent::node()
, @X
to
attribute::X
, and an omitted axis to the default axis for the node kind.
Following the rules in XPath, a leading "/"
is converted to
(root(self::node()) treat as document-node())/
(with the final
"/"
omitted for the expression "/"
on its own).
This is followed by a rewrite of the call on root
FO30, as
described in 19.8.9.18 Streamability of the root Function.
Note:
Taken together, these rewrites have the effect that a path expression such
as //a
is streamable only if the statically-determined context
item type is document-node()
, which will be the case for
example immediately within xsl:source-document
, or in a template
rule with match="/"
.
A RelativePathExpr
with more than two operands (such as
a/b/c
) is taken as a tree of binary expressions (that is,
(a/b)/c
).
The sweep of a relative path expression is the wider sweep of the two operands, where the ordering of increasing width is motionless, consuming, free-ranging.
Note:
Examples:
The sweep of a/@code
is consuming (the wider of consuming
and motionless).
The sweep of a/descendant::b
is
consuming (the wider of consuming and consuming).
The sweep of ./@code
is motionless (the wider of motionless
and motionless).
The sweep of ./a
is consuming (the wider of motionless
and consuming).
The sweep of a/following::b
is
free-ranging (the wider of consuming and free-ranging).
The sweep of ./.
is motionless (the wider of motionless
and motionless).
The posture of a relative path expression is assessed in two phases, as follows:
First, the provisional posture is determined as follows: The provisional posture of the expression is the posture of the right-hand operand, assessed with a context posture and type set to the posture and type of the left-hand operand; and the provisional sweep is the wider of the sweeps of the two operands.
If the provisional posture is roaming, then it is reassessed as follows:
[Definition: A
RelativePathExpr
is a scanning expression
if and only if it is syntactically equivalent to some motionless
pattern.]
Note:
This means that a RelativePathExpr
is a scanning expression if it conforms to the grammar for a RelativePathExprP
in the grammar for patterns (see 5.5.2 Syntax of Patterns),
and if, when considered as a pattern, the pattern is motionless according to the
rules in 19.8.10 Classifying Patterns.
In practice, the test as to whether the construct is equivalent to a pattern is likely to be made by examining the structure of the expression tree, rather than by re-parsing the lexical form of the expression against the grammar for patterns; but the outcome is the same.
If the expression is a scanning expression then:
Otherwise (if the provisional posture is not roaming, or the expression is not a scanning expression), the posture of the expression is the provisional posture.
Note:
The special rules for scanning expressions are designed to ensure
that expressions such as //section/head
are streamable. The problem
with such an expression is that it is
possible to have two nested sections A and B, where A
is the parent of B and thus precedes B in document order,
but where there are children of A that come after
children of B in document order. This means that a nested-loop
strategy for the evaluation of /descendant::section/child::head
is not guaranteed to deliver nodes in document order without a sort, and is therefore
not
a viable strategy for streaming.
However, there is a different strategy for evaluating such an expression,
which is in effect to rewrite the expression as /descendant::head[parent::section]
;
specifically, it is possible to scan all descendants in document order, looking for
a head
element that has a section
parent. Hence the term scanning expressions.
The expressions that qualify as scanning expressions are paths that can be evaluated by scanning all descendants and testing each one (independently) to see whether the elements on its ancestor axis match the specified path. The subset of expressions that qualify as scanning expressions is therefore the same as the subset that qualify as motionless patterns.
Scanning expressions cannot use positional predicates: for example //section/head[1]
is not recognized as a scanning expression because this would require information
about a streamed node (specifically, about its preceding siblings) that is not retained
during streaming.
Note:
Perhaps surprisingly, the expression .//section/head
is not a scanning
expression and is therefore not guaranteed streamable. This is because it does not
take
the syntactic form of a pattern. To make it streamable, it can be rewritten as
descendant::section/head
or as self::node()//section/head
.
Similarly, within a streamable stylesheet function whose streaming parameter is
$node
, the expression $node//section/head
is not a scanning
expression. In this case the expression does have the syntactic form of a pattern,
but the
pattern is not classified as motionless. (See 19.8.10 Classifying Patterns — a
motionless pattern cannot contain a RootedPath
.) A workaround in this case
is to rewrite the expression as $node/(descendant::section/head)
. Assuming that the
function in question declares streamability="absorbing"
, the analysis here is
that the left-hand operand ($node
) is striding and consuming, while the right hand
operand (descendant::section/head
) is crawling and consuming (because it is a
scanning expression). The expression as a whole is therefore crawling and consuming.
These are cases where an implementation might reasonably choose to relax the rules, insofar as this is permitted by 19.10 Streamability Guarantees.
Note:
Examples:
In each of the following cases, assume that the context posture is striding.
The posture of the expression a/b/c
is striding, because (under the rules for AxisStep [38]) a child axis
step evaluated with striding context posture
creates a new striding posture.
The posture of the expression a/descendant::c
is
crawling, because a descendant axis step evaluated with striding
context posture creates a new crawling posture.
The posture of the expression
../@status
is striding, because a parent axis step
evaluated with striding context posture creates a new climbing
posture, and an attribute axis step evaluated with climbing context
posture creates a new striding posture.
The posture of the expression
copy-of(.)//a/following-sibling::*
is grounded,
because the copy-of
evaluated with striding
posture creates a grounded posture, and all subsequent axis steps
leave this posture unchanged.
The expression section//head
expands to
(section/descendant-or-self::node())/child::head
. The
posture of the left-hand operand
section/descendant-or-self::node()
is crawling,
because a descendant axis step evaluated with striding context posture
creates a new crawling posture. The provisional posture of the
expression as a whole is therefore roaming, because a child axis step
evaluated with crawling context posture gives a resulting roaming posture. However, the expression
is a scanning expression (both section//head
and its expansion are
motionless patterns), so the expression as a whole has
crawling posture.
The expression section//head[1]
is
free-ranging: unlike the previous example, it contains a positional
predicate, which means that the operands do not satisfy the rules for
scanning expressions.
The sweep and posture of an AxisStep S are determined by the first of the following rules that applies:
If the context posture is grounded, then the sweep is motionless and the posture is grounded;
If the context posture is roaming, then the sweep is free-ranging and the posture is roaming;
If the statically-inferred context item type is such
that the axis will always be empty (for example, applying the child axis
to a text node or the parent axis to a document node), or if the NodeTest
is one that can never
select nodes on the chosen axis (for example, selecting attribute
nodes on the child axis), then the sweep is motionless and the posture is grounded
(because the expression is statically known to return an empty
sequence);
If all the following conditions are satisfied:
The context posture is striding
The axis is descendant
or
descendant-or-self
There is a predicate P in the PredicateList
that satisfies all the following conditions:
The static type of P is a subtype of
U{xs:decimal, xs:double, xs:float}
Neither P, nor any operand of P, at any depth provided it has the AxisStep S as its focus-setting container, is a context item expression, an axis expression, or a call on a focus-dependent function;
If the PredicateList
contains a Predicate
that
is not motionless, then the sweep is free-ranging and the posture is roaming;
Otherwise, the sweep and posture of the expression are as determined by the table below, based on the context posture, the choice of axis, and the node test. The condition “Selects elements?” is true if the U-type of S has a non-empty intersection with U{element()}.
Context posture | Axis | Selects elements? | Result posture | Sweep |
---|---|---|---|---|
Grounded | any | Grounded | Motionless | |
Climbing | self, parent, ancestor-or-self, ancestor | Climbing | Motionless | |
Climbing | attribute, namespace | Striding | Motionless | |
Striding | parent, ancestor-or-self, ancestor | Climbing | Motionless | |
Striding | self, attribute, namespace | Striding | Motionless | |
Striding | child | Striding | Consuming | |
Striding | descendant, descendant-or-self | Yes | Crawling | Consuming |
Striding | descendant, descendant-or-self | No | Striding | Consuming |
Crawling | parent, ancestor-or-self, ancestor | Climbing | Motionless | |
Crawling | attribute, namespace | Striding | Motionless | |
Crawling | self | Yes | Crawling | Motionless |
Crawling | self | No | Striding | Motionless |
Any other combination | Roaming | Free-ranging |
Note:
This analysis does not attempt to classify para[title]
as a
consuming expression; an implementation might choose
to do so.
For a filter expression F of the form B[P]
(where
B might itself be a filter expression), the posture and sweep are the first of the
following that applies:
If all the following conditions are satisfied:
B is crawling;
The static type of P is a subtype of U{xs:decimal,
xs:double, xs:float}
, and
Neither P, nor any operand of P, at any depth provided it has F as its focus-setting container, is a context item expression, an axis expression, or a call on a focus-dependent function
then the posture is striding and the sweep is the sweep of B.
Note:
This rule captures cases where it can be statically determined that
the predicate is numeric and is independent of the focus. In such
cases, the filter expression selects at most one node, and the posture
can therefore be changed from crawling to striding (if there is only
one node, there can be no overlapping trees). Examples of filter
expressions that satisfy this test are (//x)[3]
,
(//x)[$i+1]
, (//x)[index-of($a,
$b)[last()]]
, and (//x)[1 to 5]
. The last
example will actually raise a type error because 1 to 5
has no effective boolean value; but if expressions are going to fail,
it does not matter what their streamability properties are.
If P is motionless, then the posture and sweep of B;
Note:
This includes the case where B is grounded. The predicate
P is assessed with the posture of B as its
context posture, and if this is grounded, then P will
almost invariably be motionless, making the filter expression as a
whole grounded and motionless. For example if $s
is
grounded, then $s[child::*]
is also grounded. A
counter-example is the expression $s[$n = 2]
where
$n
is a reference to the first argument of a stylesheet function
that is declared-streamable: here the predicate is
not motionless, so the filter expression is roaming and
free-ranging.
Otherwise, roaming and free-ranging.
Note:
The first rule allows a construct such as <xsl:apply-templates
select="(//title)[1]"/>
, where a crawling
operand would not be guaranteed streamable.
Note:
This section is not applicable to predicates forming part of an axis step,
such as //title[1]
, as these are not technically filter
expressions. See 19.8.8.9 Streamability of Axis Steps.
Note:
This section applies to dynamic function calls written using the traditional
syntax $F(X, Y, Z)
and equally to those using the new XPath 3.1 syntax X => $F(Y, Z)
The posture and sweep of a dynamic
function call such as $F(X, Y)
are determined by the 19.8.1 General Rules for Streamability. The operands and their usages are as
follows:
The base expression that computes the function value itself (here
$F
). This has usage inspection.
The argument expressions excluding any
?
placeholders (here X
and
Y
). These have type-determined usage
dependent on ancillary information
associated with the static type of the base
expression, where available (see 19.1 Determining the Static Type of a Construct). If this information indicates
that the base expression is a function with signature
function(A, B, ...) as R
, then the first argument
X
has type-determined usage based on
the first argument type A
, the second argument
Y
has type-determined usage based on
the second argument type B
, and so on. If no function signature is available, then the
usage of each of the argument expressions is navigation.
Note:
As explained in 10.3.6 Dynamic Access to Functions, use of a dynamic function
call where the function value is bound to a focus-dependent function such as
name#0
, lang#1
, or last#0
is
likely to lead to a dynamic error if the context item is a node in a
streamed document, but this does not affect the static streamability
analysis.
Note:
Maps and arrays are functions, and it is possible to look up a value in a map
or array using a dynamic function call of the form $map($key)
or
$array($index)
. If it is statically known that the function in question
is a map or array, then it is also known that the argument type is xs:anyAtomicType
,
and that the operand usage is therefore absorption. A call that
passes a streamed node will therefore be grounded and consuming.
However, if it is not known statically that the function is a map or array, then the
expression
will generally be roaming and free-ranging.
This means it is desirable to declare the type of any variable holding a map or array.
If streamable nodes are used to lookup a value in a map or array, then it may be advisable
to use
the map:get
or array:get
functions explicitly; or, if XPath 3.1 is available,
the lookup operator (?
).
For variable references that are bound to the streaming parameter of a declared-streamable stylesheet function, see the rules for the streamability category of the containing function, under 19.8.5 Classifying Stylesheet Functions.
In all other cases, variable references are grounded and motionless.
The posture of the expression is the context posture, and the sweep is motionless.
Note:
Although .
is intrinsically motionless, when used in certain
contexts (such as data(.)
) the containing expression will be
consuming. This arises because of the operand usage: the argument to data
FO30 has
usage absorption, and the combination of a motionless operand with usage absorption
leads to the containing expression being consuming.
Similarly, if .
is used where the operand usage is navigation, the
containing expression will be free-ranging.
Note:
This section applies to static function calls written using the traditional
syntax F(X, Y, Z)
and equally to those using the new XPath 3.1 syntax X => F(Y, Z)
For calls to built-in functions, see 19.8.9 Classifying Calls to Built-In Functions.
For calls to stylesheet functions, see 19.8.5 Classifying Stylesheet Functions.
For partial function applications (where one or more of the arguments is
supplied as a ?
placeholder), see the rules at the end of this
section.
For a call to a constructor function, the 19.8.1 General Rules for Streamability apply. There is a single operand role (the argument to the function), with operand usage absorption.
For a call to an extension function, the posture and sweep are implementation-defined.
If the function call is a partial function
application (that is, if one or more of the arguments is given as a
?
placeholder), then:
If the function is focus-dependent and the context posture is not grounded, then the function call is roaming and free-ranging.
If the target of the function call is a
stylesheet function
that is declared-streamable, and if the first argument is actually
supplied (that is, this argument is not supplied as a ?
placeholder), and if the expression
that is supplied as the first argument is not grounded, then the function call is roaming and free-ranging.
If the target is an extension function, the posture and sweep are implementation-defined.
Otherwise, the general streamability rules apply.
The operands of a partial function
application are the expressions actually supplied as arguments to the
function, ignoring ?
place-holders; the corresponding
operand usage is the type-determined usage based on the declared type of that
argument.
Let F be the function to which the NamedFunctionRef
refers.
If F is focus-dependent and the
context posture is not grounded, then the NamedFunctionRef
is roaming and free-ranging.
If F is an extension function, the posture and sweep are implementation-defined.
Otherwise, the NamedFunctionRef
is grounded and
motionless.
Note:
The main intent behind these rules is to ensure that the function item returned by a named function reference does not encapsulate a reference to a streamed node.
In the case of an expression such as local-name#0
,
implementations might be able to do better by pre-evaluating the function at
the point where the named function reference occurs.
In the case of extension functions, implementations may be able to distinguish whether the function is focus-dependent, and decide the streamability of the named function reference accordingly.
An inline function declaration that textually contains a variable reference bound to a streaming parameter (of some containing stylesheet function) is roaming and free-ranging.
All other inline function declarations are grounded and motionless.
Note:
It is not possible to pass a streamed node as an argument to a call to an inline function unless the declared type of the corresponding function parameter causes the node to be atomized: see 19.8.8.11 Streamability of Dynamic Function Calls. The only other way an inline function could access a streamed node is by having the streamed node in its closure, and this is prevented by the rule above.
The posture and sweep of a map
constructor (see 21.4 Map Constructors) are the same as the
posture and sweep of the equivalent
xsl:map
instruction. The equivalent
xsl:map
instruction is formed by creating a sequence of
xsl:map-entry
instructions, one for each key/value pair in
the map expression, where the key expression becomes the value of
xsl:map-entry/@key
, and the value expression becomes the value
of xsl:map-entry/@select
; this sequence of
xsl:map-entry
instructions is then wrapped in an
xsl:map
parent instruction.
For example, the map constructor map{'red':false(),
'green':true()}
translates to the instruction:
<xsl:map> <xsl:map-entry key="'red'" select="false()"/> <xsl:map-entry key="'green'" select="true()"/> </xsl:map>
The rules for the streamability of xsl:map
appear in 19.8.4.23 Streamability of xsl:map.
See also 21.6 Maps and Streaming.
Lookup expressions for maps are defined in 21.5 The Map Lookup Operator, and are available in XSLT 3.0 whether or not XPath 3.1 is supported. Lookup expressions for arrays are defined in the XPath 3.1 specification (see Section 3.11.3 The Lookup Operator ("?") for Maps and Arrays XP31), and are available only in XSLT 3.0 processors that provide the XPath 3.1 Feature (see 27.7 XPath 3.1 Feature).
For the unary lookup operator, the posture and sweep
of the expression ?X
are
defined to be the same as the posture and sweep
of the postfix lookup expression .?X
.
For the postfix lookup expression E?K
, the general streamability rules apply as follows:
In the wildcard form of the expression, E?*
, there is only one operand, E
.
This has operand usage inspection.
Where the construct K
is an NCName, the expression E?NAME
is treated as
equivalent to E?("NAME")
.
Where the construct K
is an integer, the expression E?N
is treated as
equivalent to E?(N)
.
In the general case where K
is a parenthesized expression, the lookup expression
E?(K)
has two operands. The first operand E
has operand usage
inspection, while the second operand K
has operand usage
absorption.
This section describes the rules that determine the streamability of calls to built-in functions. These differ from user-written functions because it is known (defined in the specification) how nodes supplied as operands are used. Knowledge of the usage of each operand, together with the posture of the actual operands, is in most cases enough to determine the posture and sweep of the function result.
All the built-in functions are listed below. For most functions, a simple proforma
is shown that indicates the operand usage of each argument, using the code (A =
absorption, I = inspection, T =
transmission, N = navigation). So, for
example, the entry fn:remove(T, A)
means that for the function
fn:remove#2
, the operand usage of the first
argument is transmission, and the operand usage of the second argument is absorption. By reference to the general rules in 19.8.1 General Rules for Streamability, this demonstrates that if the context posture is striding, the posture and sweep of the expression
sum(remove(*,1))
will be grounded
and
consuming
respectively.
For functions that default one of their arguments (typically to the context item), the relevant entry shows the equivalence, and the posture and sweep can in these cases be computed by filling in the default value for the relevant argument.
Some functions do not follow the general rules, and these are listed with a link to the section where the particular rules for that function are described.
array:append(I, N)
array:filter(I, I)
array:flatten(A)
array:fold-left(I, N, I)
array:fold-right(I, N, I)
array:for-each(I, I)
array:for-each-pair(I, I, I)
array:get(I, A)
array:head(I)
array:insert-before(I, A, N)
array:join(I)
array:put(I, I, N)
array:remove(I, A)
array:reverse(I)
array:size(I)
array:sort(I)
array:sort(I, A)
array:sort(I, A, I)
array:subarray(I, A)
array:subarray(I, A, A)
array:tail(I)
fn:abs(A)
fn:accumulator-after
– See 19.8.9.1 Streamability of the accumulator-after Function
fn:accumulator-before
– See 19.8.9.2 Streamability of the accumulator-before Function
fn:adjust-date-to-timezone(A)
fn:adjust-date-to-timezone(A, A)
fn:adjust-dateTime-to-timezone(A)
fn:adjust-dateTime-to-timezone(A, A)
fn:adjust-time-to-timezone(A)
fn:adjust-time-to-timezone(A, A)
fn:analyze-string(A, A)
fn:analyze-string(A, A, A)
fn:apply(A, I)
fn:available-environment-variables()
fn:available-system-properties()
fn:avg(A)
fn:base-uri()
– Equivalent to fn:base-uri(.)
fn:base-uri(I)
fn:boolean(I)
fn:ceiling(A)
fn:codepoint-equal(A, A)
fn:codepoints-to-string(A)
fn:collation-key(A)
fn:collation-key(A, A)
fn:collection()
fn:collection(A)
fn:compare(A, A)
fn:compare(A, A, A)
fn:concat(A, A, A)
fn:contains(A, A)
fn:contains(A, A, A)
fn:contains-token(A, A)
fn:contains-token(A, A, A)
fn:copy-of()
– Equivalent to fn:copy-of(.)
fn:copy-of(A)
fn:count(I)
fn:current
– See 19.8.9.3 Streamability of the current Function
fn:current-date()
fn:current-dateTime()
fn:current-group
– See 19.8.9.4 Streamability of the current-group Function
fn:current-grouping-key
– See 19.8.9.5 Streamability of the current-grouping-key
Function
fn:current-merge-group
– See 19.8.9.6 Streamability of the current-merge-group
Function
fn:current-merge-key
– See 19.8.9.7 Streamability of the current-merge-key Function
fn:current-output-uri()
fn:current-time()
fn:data()
– Equivalent to fn:data(.)
fn:data(A)
fn:dateTime(A, A)
fn:day-from-date(A)
fn:day-from-dateTime(A)
fn:days-from-duration(A)
fn:deep-equal(A, A)
fn:deep-equal(A, A, A)
fn:deep-equal(A, A)
fn:deep-equal(A, A, A)
fn:default-collation()
fn:default-language()
fn:distinct-values(A)
fn:distinct-values(A, A)
fn:doc(A)
fn:doc-available(A)
fn:document(A)
fn:document(A, I)
fn:document-uri()
– Equivalent to fn:document-uri(.)
fn:document-uri(I)
fn:element-available(A)
fn:element-with-id(x)
– Equivalent to fn:element-with-id(x, .)
fn:element-with-id(A, N)
fn:empty(I)
fn:encode-for-uri(A)
fn:ends-with(A, A)
fn:ends-with(A, A, A)
fn:environment-variable(A)
fn:error()
– Equivalent to fn:error(x, x, x, x, x, .)
fn:error(x)
– Equivalent to fn:error(x, x, x, x, .)
fn:error(x, x)
– Equivalent to fn:error(x, x, .)
fn:error(A, A, N)
fn:escape-html-uri(A)
fn:exactly-one(T)
fn:exists(I)
fn:false()
fn:filter(N, I)
fn:floor(A)
fn:fold-left(N, A, I)
fn:fold-right
– See 19.8.9.9 Streamability of the fold-right Function
fn:for-each(N, I)
fn:for-each-pair(N, N, I)
fn:format-date(A, A)
fn:format-date(A, A, A, A, A)
fn:format-dateTime(A, A)
fn:format-dateTime(A, A, A, A, A)
fn:format-integer(A, A)
fn:format-integer(A, A, A)
fn:format-number(A, A)
fn:format-number(A, A, A)
fn:format-time(A, A)
fn:format-time(A, A, A, A, A)
fn:function-arity(A)
fn:function-available(A)
fn:function-available(A, A)
fn:function-lookup
– See 19.8.9.12 Streamability of the function-lookup Function
fn:function-name(A)
fn:generate-id()
– Equivalent to fn:generate-id(.)
fn:generate-id(I)
fn:has-children()
– Equivalent to fn:has-children(.)
fn:has-children(I)
fn:head(T)
fn:hours-from-dateTime(A)
fn:hours-from-duration(A)
fn:hours-from-time(A)
fn:id(x)
– Equivalent to fn:id(x, .)
fn:id(A, N)
fn:idref(x)
– Equivalent to fn:idref(x, .)
fn:idref(A, N)
fn:implicit-timezone()
fn:in-scope-prefixes(I)
fn:index-of(A, A)
fn:index-of(A, A, A)
fn:innermost
– See 19.8.9.13 Streamability of the innermost Function
fn:insert-before(T, A, T)
fn:iri-to-uri(A)
fn:json-doc(A)
fn:json-doc(A, I)
fn:json-to-xml(A)
fn:json-to-xml(A, I)
fn:key(x, x)
– Equivalent to fn:key(x, x, /)
fn:key(A, A, N)
fn:lang(x)
– Equivalent to fn:lang(x, .)
fn:lang(A, I)
fn:last
– See 19.8.9.14 Streamability of the last Function
fn:load-xquery-module(A)
fn:load-xquery-module(A, I)
fn:local-name()
– Equivalent to fn:local-name(.)
fn:local-name(I)
fn:local-name-from-QName(A)
fn:lower-case(A)
fn:matches(A, A)
fn:matches(A, A, A)
fn:max(A)
fn:max(A, A)
fn:min(A)
fn:min(A, A)
fn:minutes-from-dateTime(A)
fn:minutes-from-duration(A)
fn:minutes-from-time(A)
fn:month-from-date(A)
fn:month-from-dateTime(A)
fn:months-from-duration(A)
fn:name()
– Equivalent to fn:name(.)
fn:name(I)
fn:namespace-uri()
– Equivalent to fn:namespace-uri(.)
fn:namespace-uri(I)
fn:namespace-uri-for-prefix(A, I)
fn:namespace-uri-from-QName(A)
fn:nilled()
– Equivalent to fn:nilled(.)
fn:nilled(I)
fn:node-name()
– Equivalent to fn:node-name(.)
fn:node-name(I)
fn:normalize-space()
fn:normalize-space(A)
fn:normalize-unicode(A)
fn:normalize-unicode(A, A)
fn:not(I)
fn:number()
– Equivalent to fn:number(.)
fn:number(A)
fn:one-or-more(T)
fn:outermost
– See 19.8.9.15 Streamability of the outermost Function
fn:parse-ietf-date(A)
fn:parse-json(A)
fn:parse-json(A, I)
fn:parse-xml(A)
fn:parse-xml-fragment(A)
fn:path()
– Equivalent to fn:path(.)
fn:path(N)
fn:position
– See 19.8.9.16 Streamability of the position Function
fn:prefix-from-QName(A)
fn:QName(A, A)
fn:random-number-generator()
fn:random-number-generator(A)
fn:regex-group(A)
fn:remove(T, A)
fn:replace(A, A, A)
fn:replace(A, A, A, A)
fn:resolve-QName(A, I)
fn:resolve-uri(A)
fn:resolve-uri(A, A)
fn:reverse
– See 19.8.9.17 Streamability of the reverse Function
fn:root
– See 19.8.9.18 Streamability of the root Function
fn:round(A)
fn:round(A, A)
fn:round-half-to-even(A)
fn:round-half-to-even(A, A)
fn:seconds-from-dateTime(A)
fn:seconds-from-duration(A)
fn:seconds-from-time(A)
fn:serialize(A)
fn:serialize(A, A)
fn:snapshot()
– Equivalent to fn:snapshot(.)
fn:snapshot(A)
fn:sort(N)
fn:sort(N, A)
fn:sort(N, A, I)
fn:starts-with(A, A)
fn:starts-with(A, A, A)
fn:static-base-uri()
fn:stream-available(A)
fn:string()
– Equivalent to fn:string(.)
fn:string(A)
fn:string-join(A)
fn:string-join(A, A)
fn:string-length()
fn:string-length(A)
fn:string-to-codepoints(A)
fn:subsequence(T, A)
fn:subsequence(T, A, A)
fn:substring(A, A)
fn:substring(A, A, A)
fn:substring-after(A, A)
fn:substring-after(A, A, A)
fn:substring-before(A, A)
fn:substring-before(A, A, A)
fn:sum(A)
fn:sum(A, A)
fn:system-property(A)
fn:tail(T)
fn:timezone-from-date(A)
fn:timezone-from-dateTime(A)
fn:timezone-from-time(A)
fn:tokenize(A)
fn:tokenize(A, A)
fn:tokenize(A, A, A)
fn:trace(A)
fn:trace(T, A)
fn:transform(I)
fn:translate(A, A, A)
fn:true()
fn:type-available(A)
fn:unordered(T)
fn:unparsed-entity-public-id(x)
– Equivalent to fn:unparsed-entity-public-id(x, /)
fn:unparsed-entity-public-id(A, I)
fn:unparsed-entity-uri(x)
– Equivalent to fn:unparsed-entity-uri(x, /)
fn:unparsed-entity-uri(A, I)
fn:unparsed-text(A)
fn:unparsed-text(A, A)
fn:unparsed-text-available(A)
fn:unparsed-text-available(A, A)
fn:unparsed-text-lines(A)
fn:unparsed-text-lines(A, A)
fn:upper-case(A)
fn:uri-collection()
fn:uri-collection(A)
fn:xml-to-json(A)
fn:xml-to-json(A, I)
fn:year-from-date(A)
fn:year-from-dateTime(A)
fn:years-from-duration(A)
fn:zero-or-one(T)
map:contains(I, A)
map:entry(A, N)
map:find(I, A)
map:for-each(I, I)
map:get(I, A)
map:keys(I)
map:merge(I)
map:merge(I, I)
map:put(I, A, N)
map:remove(I, A)
map:size(I)
math:acos(A)
math:asin(A)
math:atan(A)
math:atan2(A, A)
math:cos(A)
math:exp(A)
math:exp10(A)
math:log(A)
math:log10(A)
math:pi()
math:pow(A, A)
math:sin(A)
math:sqrt(A)
math:tan(A)
accumulator-after
FunctionSee also 18.2.9 Streamability of Accumulators.
The posture of the function call is in all cases grounded.
The sweep is determined by applying the following rules, in order:
If the first argument (the accumulator name) is not motionless, the function is free-ranging.
If the context posture is grounded, the function is motionless.
If the context item type has an empty intersection with U{document-node(), element()} (that is, if the context item cannot have children), the function is motionless.
If the function call is contained in the select
expression
or contained sequence constructor of an
xsl:accumulator-rule
specifying
phase="start"
, then it is free-ranging.
If the function call is contained in the select
expression
or contained sequence constructor of an
xsl:accumulator-rule
specifying
phase="end"
, then it is motionless.
If no enclosing node of the function call is part of a sequence constructor, then it is free-ranging. For this purpose, the enclosing nodes of a function call are the attribute or text node that immediately contains the XPath expression in which the function call appears, and its ancestors.
If the focus-setting container of the function call is different from the focus-setting container of the innermost containing instruction, then the function is free-ranging.
If no enclosing node N of the function call has a preceding sibling node P such that (a) N and P are part of the same sequence constructor, and (b) the sweep of P is consuming, then the function call is consuming. (The term enclosing node is defined above.)
Otherwise, the function call is motionless.
Note:
The following notes apply to the above rules with matching numbers:
This rule prevents the accumulator name being computed by reading the streamed source document. This is disallowed primarily because there is no conceivable use case for doing it.
If the context posture is grounded, then the target of the accumulator is not a streamed node, so no streaming restrictions apply.
If the context item is a childless node (such as a text node), then
both the pre-descent and post-descent values of the accumulator can be
computed before evaluating any user-written constructs that access
this node; there are therefore no constraints on where a call to
accumulator-after
can appear.
This rule ensures that when computing the pre-descent value of an accumulator for a particular streamed node, the post-descent values of accumulators for that node are not available.
This rule states that the post-descent value of an accumulator is allowed to depend on the post-descent values of other accumulators for the same node. There is a rule preventing cycles [see ERR XTDE3400].
This rule prevents the use of the function (when applied to a streamed
node) in contexts like the use
attribute of
xsl:key
. It
allows its use in the attributes of an instruction or literal result element, or in a text value template. It does not allow use in an
xsl:sort
or xsl:param
element,
as these elements do not form part of a sequence constructor (see
5.7 Sequence Constructors).
This rule prevents the use of the function (when applied to a streamed
node) in contexts such as predicates, or the right-hand side of the
/
operator. The focus for evaluation of the function must be the
same as the focus for a containing sequence constructor. Sequence
constructors are treated differently from all other constructs for
this purpose in that their operands (the contained instructions) are
treated as ordered: in conjunction with the next rule, this rule is
assuming that instructions in a sequence constructor that follow a
consuming instruction are evaluated after the
consuming instruction and therefore have access
to the post-descent accumulator value.
This rule is subtle, and has a number of consequences. In these notes, the term instruction should be read as including all nodes making up a sequence constructor, including XSLT instructions, extension instructions, literal result elements, and text nodes containing text value templates.
In a sequence constructor that contains a consuming instruction such as
<xsl:apply-templates/>
, it allows any
number of calls on accumulator-after
to
appear in instructions that follow the call on
<xsl:apply-templates/>
.
In such a sequence constructor it prevents a call on
accumulator-after
from appearing in an
instruction that precedes the
<xsl:apply-templates/>
, because there
would then be two consuming
instructions.
In a sequence constructor that contains calls on
accumulator-after
, and contains no other
consuming construct, the first
instruction that contains a call on
accumulator-after
is consuming (unless
it contains more than one such call, in which case it is
free-ranging), and subsequent instructions containing such a
call are motionless. So it is possible to have two or more calls
on accumulator-after
provided they appear
in different instructions, which allows the analysis to assume
an order of execution.
It prevents a call on accumulator-after
from appearing in the same instruction as another consuming
construct: for example it disallows concat(child::p,
accumulator-after('a'))
. This rule preserves the
ability to evaluate the arguments of the concat
function in any order.
It disallows a call on accumulator-after
from appearing in a sequence constructor that is required to be
motionless, for example within xsl:sort
.
The reference to a “preceding sibling node within the same
sequence constructor” is carefully worded to ensure that
preceding siblings among the children of
xsl:fork
are not taken into account; the
children of xsl:fork
are sibling instructions,
but do not constitute a sequence constructor. The term also excludes elements such as
xsl:param
and xsl:sort
that may precede a sequence constructor but are not part of
it.
The final rule states that if none of the previous rules apply, the
function is considered motionless. This applies when the
accumulator-after
appears after a consuming
instruction within the same sequence constructor.
Note also that a call to accumulator-after
can
safely appear within a construct such as a named template or
(non-streamable) stylesheet function; this is safe because the rules
ensure that in such situations, the context item cannot be a streamed
node.
Dynamic invocation of accumulator-after
is covered by the
rules in 10.3.6 Dynamic Access to Functions. These rules ensure that a function
item cannot include a streamed node in its closure; circumventing the
streamability rules for accumulator-after
by making a
dynamic call is therefore not possible.
accumulator-before
FunctionSee also 18.2.9 Streamability of Accumulators.
The posture and sweep of the function call are assessed as follows:
If the argument to accumulator-before
is motionless,
the function call is grounded and motionless.
Otherwise, the function call is roaming and free-ranging.
current
FunctionThe sweep and posture of a call to the
current
function are determined as follows:
If the call appears within a pattern, then climbing and motionless.
Note:
The call to current
will always be within a predicate of the pattern.
The use of climbing posture here allows predicates such as [@class = current()/@class]
,
while disallowing downwards navigation from the node returned by the function.
Otherwise, let E be the outermost containing XPath expression of the call
to the current
function.
If the context posture of E is grounded, then motionless and grounded.
If the path in the expression tree that connects the call on
current
to E (excluding E
itself) contains an expression that is a higher-order operand of its parent expression, then
motionless and climbing.
Note:
Many common uses of the current
, such as
//p[@class=current()/@class]
, fall into this category:
a predicate is a higher-order operand of its containing filter
expression.
The use of climbing posture here might seem
unrelated to its usual connection with the ancestor axis. The
explanation (apart from the fact that it happens to produce the right
results) lies in the fact that at the point where the
current
call is evaluated, the node it returns
will always be an ancestor-or-self of the context node, as a
consequence of the fact that the containing XPath expression is
required to be either motionless or consuming.
The effect of the rule is to allow
expressions such as //*[name() = name(current())]
or
//*[@ref = current()/@id]
.
Otherwise, the posture is the context posture, and the sweep is motionless.
current-group
FunctionThe sweep and posture of a call C to the
current-group
function are as follows:
If all the following conditions are true:
C has a containing xsl:for-each-group
instruction (call it F)
The path in the construct tree that connects C to the sequence constructor forming the body of F is such that no child construct is a higher-order operand of its parent
The focus-setting container of C is F
then the sweep and posture of
C are the sweep and posture of the select
expression of
F.
Otherwise, roaming and free-ranging.
Note:
Informally, for streamed evaluation to be possible, a call to
current-group
must not appear in a construct that is
evaluated repeatedly. For example, the expression for $i in 1 to 10
return current-group()
would not be streamable.
current-grouping-key
FunctionA call to the
current-grouping-key
function is grounded and
motionless.
current-merge-group
FunctionA call to the
current-merge-group
function is grounded and motionless.
Note:
This is because the nodes to be merged are always snapshots, and therefore grounded: see 15.4 Streamable Merging.
current-merge-key
FunctionA call to the current-merge-key
function is grounded and motionless.
fold-left
FO30 FunctionThe function call fold-left($seq, $zero, $f)
, follows the general streamability rules, with the first argument
$seq
having type-determined usage based on
the type of the second argument of the function supplied as
$f
.
For example, given the call fold-left(/*/transaction, 0, function($x as
xs:decimal, $y as xs:decimal) as xs:decimal {$x+$y})
, the operand usage of the argument /*/transaction
is
determined by the declared type of $y
, namely
xs:decimal
. Since this is an atomic type, the type-determined usage is absorption. Applying
this to the general streamability rules, the function call is grounded and consuming.
fold-right
FO30 FunctionThe function follows the general streamability rules, with the first argument having operand usage navigation to reflect the fact that the supplied sequence is processed in reverse order.
Note:
The same considerations apply as for the reverse
FO30
function: see 19.8.9.17 Streamability of the reverse Function.
for-each
FO30 FunctionThe function call for-each($seq, $f)
, follows the general streamability rules, with the first argument
$seq
having type-determined usage based on
the type of the (single) argument of the function supplied as
$f
.
For example, given the call for-each(/*/transaction, function($x as
xs:decimal) as xs:decimal {abs($x)})
, the operand usage of the argument /*/transaction
is
determined by the declared type of $x
, namely
xs:decimal
. Since this is an atomic type, the type-determined usage is absorption. Applying
this to the general streamability rules, the function call is grounded and consuming.
Note:
In practice, the filter
FO30 function is streamable if
either (a) the supplied sequence is grounded, or (b) the supplied function
is statically known to atomize its argument.
for-each-pair
FO30 FunctionThe function call for-each($seq1, $seq2, $f)
, follows the general streamability rules, where:
The first argument $seq1
has type-determined usage based on the type of the first
argument of the function supplied as $f
.
The second argument $seq2
has type-determined usage based on the type of the second
argument of the function supplied as $f
Note:
In practice, the for-each-pair
FO30 function is streamable
provided (a) at most one of the input sequences is consuming, and (b) either
(i) that input sequence is grounded, or (ii) the supplied function is
statically known to atomize the relevant argument.
If it is necessary to combine two sequences that are both streamed, consider
using xsl:merge
.
function-lookup
FO30 FunctionSee 10.3.6 Dynamic Access to Functions for special rules that relate to
streamability of calls to the function-lookup
FO30
function.
With the caveats given there, the function follows the general streamability rules, for a function with two arguments that both have operand usage absorption.
innermost
FO30 FunctionThe function follows the general streamability rules, with
the first argument having operand usage
navigation. This is to reflect the fact that the processing
is not strictly sequential: it cannot be determined that a node is part of the
result sequence of innermost
FO30 until all its descendants
have been read.
last
FO30 FunctionIf the context posture for a call on the
last
FO30 function is striding,
crawling, or roaming, then the
posture of the function is roaming,
and the sweep is free-ranging.
In all other cases the function is grounded and motionless.
Note:
The cases where last
FO30 can be used without affecting
streamability are where the context item is either grounded or climbing. The latter condition
makes expressions like ancestor::*[@xml:space][last()]
streamable.
There are special rules restricting the use of last
FO30
in the predicate of a pattern: see 19.8.10 Classifying Patterns.
Note that there are no restrictions preventing the
use of last()
when the context posture is grounded. The implications of
this are discussed in 19.7 Grounded Consuming Constructs. In the case where
the sequence being processed is delivered by a consuming expression, using last()
may result in this sequence being buffered in memory.
outermost
FO30 FunctionThe single argument to this function has operand usage transmission.
The streamability of the function call follows the general streamability rules with one exception: if the posture of the argument is crawling, then the posture of the result is striding.
Note:
There are cases where the streaming rules allow the construct
outermost(//para)
but do not allow //para
; the
function can therefore be useful in cases where it is known that
para
elements will not be nested, as well as cases where the
application actually wishes to process all para
elements except
those that are nested within another.
By contrast, the innermost
FO30 function offers no
streaming benefits. Although it delivers a subset of the input nodes as its
result, in the correct order, it is classed as navigational because it needs
to look ahead in the input stream before deciding whether a node can be
included in the result.
position
FO30 FunctionThe position
FO30 function follows the general streamability rules. Since it has no operands, this means
it is grounded and motionless.
Note:
Within an expression, there are no special difficulties in evaluating the
position
FO30 function.
It does have special treatment within a predicate of a pattern, however: a pattern is not motionless if it contains a
call to position
FO30, as explained in 19.8.10 Classifying Patterns.
reverse
FO30 FunctionThe reverse
FO30 function follows the general streamability rules, with its operand classified as
having operand usage
navigation.
Note:
This means in effect that a call on reverse
FO30 is not
streamable unless the operand is grounded. This may cause few surprises:
The expression reverse(/*/emp/copy-of())
is considered
streamable, although all the emp
elements will typically
need to be in memory at the same time. The explanation here is that
the streamability rules do not attempt to restrict the amount of
memory used for data that is explicitly copied by use of a function
such as copy-of
.
The expression reverse(ancestor::*)/name()
is considered
non-streamable, because the operand is not grounded. This problem can
be circumvented by rewriting the expression as
reverse(ancestor::*/name())
root
FO30 FunctionThe zero-argument function root()
is equivalent to
root(.)
.
Given the expression root(X)
, if the static type of X
is U{document-node()}, and if its posture is striding, then
root(X)
is rewritten as X
. Otherwise, it is
rewritten as head((X)/ancestor-or-self::node())
. Streamability
analysis is then applied to the rewritten expression.
Note:
Because path expressions starting with /
are rewritten to use
the root
FO30 function, this ensures that a leading slash
is ignored if the context item is a document node, for example within a
template rule with match="/"
. This improves streamability,
because upwards navigation followed by downward navigation is
disallowed.
Note:
Patterns differ from other kinds of construct in that they are not composable in the same way. It is best to think of a pattern as specialized syntax for a function that takes an item as its argument and returns a boolean: true if the pattern matches the item, otherwise false. The static type of a pattern is therefore taken as U{xs:boolean} (this is not to be confused with the type of the items that the pattern is capable of matching).
The sweep of a pattern is either motionless or free-ranging. (Although there are patterns that could in principle be evaluated by consuming the element node that they match, these are of no interest in the analysis, so they are classified as free-ranging.)
The posture of a pattern is grounded if the pattern is motionless, or roaming otherwise. (This reflects the fact that a pattern always returns a boolean result; it never returns a node in a streamed document.)
Informally, a motionless pattern is one that can be evaluated by a streaming processor when the input stream is positioned at the start of the node being matched, without advancing the input stream.
A pattern is motionless if and only if it satisfies all the following conditions:
The pattern does not contain a RootedPath.
If the pattern contains predicates, then every top-level
Predicate
in the pattern satisfies all the following
conditions:
The expression immediately contained in the predicate is motionless, when assessed with a context posture of striding, and a context item type set to the static type of the expression to which the predicate applies, determined using the rules in 19.1 Determining the Static Type of a Construct.
The predicate is a non-positional predicate.
The use of the term top-level in this rule means that predicates that are nested within other predicates do not themselves have to be non-positional, though they may play a role in the analysis of top-level predicates.
The pattern does not contain (at any depth) a variable reference that is bound to a streaming parameter. (See 19.8.8.14 Streamability of Static Function Calls).
[Definition: A predicate is a non-positional predicate if it satisfies both of the following conditions:
The predicate does not contain a function call or named function reference to any of the following functions, unless that call or reference occurs within a nested predicate:
position
FO30
last
FO30
function-lookup
FO30.
Note:
The exception for nested predicates is there to ensure that patterns
such as match="p[@code = $status[last()]]
are not disqualified.
The expression immediately contained in the predicate is a non-numeric expression. An expression is non-numeric if the intersection of its static type (see 19.1 Determining the Static Type of a Construct) with U{xs:decimal, xs:double, xs:float} is U{}.
]
Note:
A non-positional predicate can be evaluated by considering each item in the filtered sequence independently; the result never depends on the position of other items in the sequence or the length of the sequence.
A pattern that is not motionless is classified as free-ranging.
The following list shows examples of motionless patterns:
/
*
/*
p
p|q
p/q
p[@status='red']
p[base-uri()]
p[@class or @style]
p[@status]
p[@status = $status-codes[1]]
p[@class | @style]
p[contains(@class, ':')]
p[substring-after(@class, ':')]
p[ancestor::*[@xml:lang]]
text()[starts-with(., '$')]
@price
@price[starts-with(., '$')]
//p/text()[. = 'Introduction']
document-node(element(html))
(Note:
this is classified as motionless even though testing a document node against
the pattern might require a small amount of look-ahead.)
The following list shows examples of patterns that are not motionless, explaining why not:
id('abc')
(contains a RootedPath
)
$doc//p
(contains a RootedPath
)
p[b]
(the predicate is not motionless)
p[. = 'Introduction']
(the predicate is not motionless)
p[starts-with(., '$')]
(the predicate is not motionless)
p[preceding-sibling::p[1] = '']
(the predicate is not
motionless)
p[1]
(contains a positional predicate: return type is
numeric)
p[$pnum + 1]
(contains a positional predicate: return type is
numeric)
p[data(@status)]
(contains a positional predicate: return type
is potentially numeric)
p[position() gt 2]
(contains a positional predicate: calls
position()
)
p[last()]
(contains a positional predicate: calls
last()
)
The examples in this section are intended to illustrate how the streamability rules are applied “top down” to establish whether template rules are guaranteed streamable.
Consider the following template rule, where mode s
is defined with
streamable="yes"
:
<xsl:template match="para" mode="s"> <div class="para"> <xsl:apply-templates mode="s"/> </div> </xsl:template>
The processor is required to establish that this template meets the streamability rules. Specifically, as stated in 6.6.4 Streamable Templates, it must satisfy three conditions:
The match pattern must be motionless.
The body of the template rule must be grounded.
The initializers of any template parameters must be motionless.
The third condition is satisfied trivially because there are no parameters.
The first rule depends on the rules for assessing patterns, which are given in
19.8.10 Classifying Patterns. This pattern is motionless because (a)
it does not contain a RootedPath
, and (b) it contains no
predicates.
So it remains to determine that the body of the template is grounded. The proof of this is as follows:
The sequence constructor forming the body of the template is assessed
according to the rules in 19.8.3 Classifying Sequence Constructors, which tell us that there is a single operand (the
<div>
literal result element) which has operand usage
U = transmission.
The assessment of the sequence constructor uses the general streamability rules. These rules require us to determine the type T, sweep S, posture P, and usage U of each operand. We have already established that there is a single operand, with U = transmission. Section 19.1 Determining the Static Type of a Construct tells us that for all instructions, we can take T = U{*}. The posture P and sweep S of the literal result element are established as follows:
The rules for literal result elements (specifically the
<div>
element) are given in 19.8.4.1 Streamability of Literal Result Elements. This particular
literal result element has only one operand (its contained sequence
constructor), with operand usage
U = absorption.
The general streamability rules again apply. Again
the static type
T of the operand is U{*}
, and we need to
determine the posture
P and sweep
S.
To determine the posture and sweep of this sequence constructor (the
one that contains the xsl:apply-templates
instruction) we refer again to the general streamability rules.
The sequence constructor has a single operand (the
xsl:apply-templates
instruction); again
U = transmission, T
= U{*}.
The posture
P and sweep
S of the xsl:apply-templates
instruction are established as follows:
The rules that apply are in 19.8.4.5 Streamability of xsl:apply-templates.
Rule 1 does not apply because the select
expression (which defaults to child::node()
)
is not grounded. This is a consequence
of the rules in 19.8.8.9 Streamability of Axis Steps, specifically:
The context posture of the axis step is established by the template rule as a whole, as striding.
Therefore rules 1 and 2 do not apply.
The statically-inferred context item type is derived
from the match pattern (match="para"
).
This gives a type of U{element()}. The
child axis for element nodes is not necessarily
empty, so rule 3 does not apply.
Rule 4 does not apply because there are no predicates.
So the posture and sweep of the axis step
child::node()
are given by the table
in rule 5. The entry for (context posture =
striding, axis = child) gives a posture of striding and a sweep of consuming.
So the select
expression is not
grounded. (The same result can
be reached intuitively: an expression that selects
streamed nodes will never be grounded.)
Rule 2 does not apply because there is no
xsl:sort
element.
Rule 3 does not apply because the mode is declared with
streamable="yes"
.
So the posture
P and sweep
S of the xsl:apply-templates
instruction are established by the general streamability rules, as follows:
There is a single operand, the implicit
select="child::node()"
expression,
with usage U = absorption.
We have already established that for this operand, the posture P = striding and the sweep S = consuming.
By the rules in 19.1 Determining the Static Type of a Construct, the type
T of the select
expression
is node()
.
In the general streamability rules, the adjusted sweep S′ for an operand with (P = striding, U = absorption) is consuming,
Rule 2(d) then applies, so the
xsl:apply-templates
instruction
is consuming and grounded.
So the sequence constructor that contains the
xsl:apply-templates
instruction has one
operand with U = transmission,
T = item()
, P = grounded, S = consuming. Rule 2(d) of the general streamability rules applies, so the
sequence constructor itself has P = grounded, S = consuming.
So the literal result element has one operand with U =
absorption, T = item()
,
P = grounded, S =
consuming. Rule 2(d) of the general streamability rules applies, so the literal
result element has P = grounded,
S = consuming.
So the sequence constructor containing the literal result element has one
operand with U = transmission, T =
item()
, P = grounded,
S = consuming. Rule 2(d) of the general streamability rules applies, so this sequence
constructor itself has P = grounded,
S = consuming.
So we have established that the sequence constructor forming the body of the template rule is grounded.
Therefore, since the other conditions are also satisfied, the template is guaranteed-streamable.
The analysis presented above could have been simplified by taking into account the fact that the streamability properties of a sequence constructor containing a single instruction are identical to the properties of that instruction. This simplification will be exploited in the next example.
Consider the following template rule, where mode s
is defined with
streamable="yes"
:
<xsl:template match="transactions[@currency='USD']" mode="s"> <total><xsl:value-of select="sum(transaction/@value)"/></total> </xsl:template>
Again, as stated in 6.6.4 Streamable Templates, it must satisfy three conditions:
The match pattern must be motionless.
The body of the template rule must be grounded.
The initializers of any template parameters must be motionless.
The third condition is satisfied trivially because there are no parameters.
The first rule depends on the rules for assessing patterns, which are given in
19.8.10 Classifying Patterns. This pattern is motionless because (a)
it is not a RootedPath
, and (b) every predicate is motionless and non-positional. The analysis that proves the predicate is motionless
and non-positional proceeds as follows:
First establish that that the expression @currency='USD'
is
motionless, as follows:
The predicate is a general comparison (GeneralComp
) which
follows the general streamability rules.
There are two operands: an AxisStep
with a defaulted
ForwardAxis
, and a Literal
. Both operand
roles are absorption.
The left-hand operand has
type T = attribute()
. Its posture and sweep are determined by
the rules in 19.8.8.9 Streamability of Axis Steps. The
context posture is striding, so the posture and sweep
are determined by the entry in the table (rule 5) with context posture
= striding, axis = attribute
: that
is, the result posture is striding and the sweep
is motionless.
The right-hand operand, being a literal, is grounded and motionless.
In the general streamability rules, rule 2(e) applies, so the predicate is grounded and motionless
Now establish that that the expression @currency='USD'
is
non-positional, as
follows:
Rule 1 is satisfied: the predicate does not call
position
FO30, last
FO30, or
function-lookup
FO30.
Rule 2 is satisfied: the expression @currency='USD'
is
non-numeric. The static type of the expression is
determined using the rules in 19.1 Determining the Static Type of a Construct
as U{xs:boolean}, and this has no intersection with
U{xs:decimal, xs:double, xs:float}.
So both conditions in 19.8.10 Classifying Patterns are satisfied, and the pattern is therefore motionless.
It remains to show that the body of the template rule is grounded. The proof of this is as follows. Unlike the previous example, the analysis is shown in simplified form; in particular the two sequence constructors which each contain a single instruction are ignored, and replaced in the construct tree by their contained instruction.
We need to show that the <total>
literal result element is grounded.
The rules that apply are in 19.8.4.1 Streamability of Literal Result Elements.
These rules refer to the general streamability rules.
There is one operand, the xsl:value-of
child element, which
has operand usage
U = absorption, and type T =
item()
.
So we need to determine the posture and sweep of the xsl:value-of
instruction.
The rules are given in 19.8.4.40 Streamability of xsl:value-of.
The general streamability rules apply. There is
one operand, the expression sum(transaction/@value)
,
which has operand usage
U = absorption.
The type T of this operand is the return type defined in
the signature of the sum
FO30 function, that is,
xs:anyAtomicType
.
The posture P and sweep S are established as follows:
The rules that apply to the call on sum
FO30
are given in 19.8.9 Classifying Calls to Built-In Functions.
The relevant proforma is fn:sum(A)
, indicating that
the general streamability rules apply, and
that there is a single operand with usage U =
absorption.
The type T of the operand
transaction/@value
is determined (by the rules
in 19.1 Determining the Static Type of a Construct) as
attribute()
.
The posture
P and sweep
S of the operand transaction/@value
are
determined by the rules in 19.8.8.8 Streamability of Path Expressions, as follows:
The expression is expanded to
child::transaction/attribute::value
.
The posture and sweep of the left-hand operand
child::transaction
are determined by the
rules in 19.8.8.9 Streamability of Axis Steps, as
follows:
The context posture is striding, because the focus-setting container is the template rule itself.
The context item type is
element()
, based on the match type of the pattern
match="transactions[@currency='USD']"
.
Rules 1 and 2 do not apply because the context posture is striding.
Rule 3 does not apply because the child
axis applied to an element node is not necessarily
empty.
Rule 4 does not apply because there are no predicates.
Rule 5 applies, and the table entry with context
posture = striding, axis =
child
gives a result posture of striding
and a sweep of consuming.
The posture of the relative path
expression
child::transaction/attribute::value
is
therefore the posture of its right-hand operand
attribute::value
, assessed with a context posture of striding. This is determined by the rules in
19.8.8.9 Streamability of Axis Steps, as
follows:
The context posture, as we have seen, is striding.
The context item type is
element()
, based on the type of the
left-hand operand
child::transaction
.
Rules 1 and 2 do not apply because the context posture is striding.
Rule 3 does not apply because the
attribute
axis applied to an element
node is not necessarily empty.
Rule 4 does not apply because there are no predicates.
Rule 5 applies, and the table entry with context
posture = striding, axis =
attribute
gives a result posture of striding and a sweep of
motionless.
The posture of the relative path
expression
child::transaction/attribute::value
is
therefore striding.
The sweep of the relative path
expression
child::transaction/attribute::value
is the
wider of the sweeps of its two operands, namely consuming and motionless. That is, it is consuming.
So the first and only operand to the call on sum()
has U = absorption, T
= attribute()
, P = climbing, and S = consuming
Rule 1(b) of the general streamability rules computes the adjusted sweep S′. Rule 1(b)(iii)(A) applies, so the effective operand usage U′ is inspection. Rule 1(b)(iii)(A) then computes the adjusted sweep from the table entry for P = climbing, U′ = inspection; this shows S′ = S, that is, consuming.
Rule 2(d) now applies, so the call on sum()
is
grounded and consuming.
Since the xsl:value-of
instruction has one operand
with U = absorption, T =
xs:anyAtomicType
, P = grounded, and S = consuming, rule 2(d) again applies, and the xsl:value-of
instruction is grounded and consuming.
Since the literal result element has one operand with U =
absorption, T = item()
,
P = grounded, and S = consuming, rule 2(d) again applies, and the literal result
element is grounded and consuming.
Therefore the body of the template rule is grounded, and since the other conditions are also satisfied, it is guaranteed-streamable.
Consider the following code, which is designed to process a transaction file containing transactions in chronological order, and output the total value of the transactions for each day.
<xsl:template name="go"> <out> <xsl:source-document streamable="yes" href="transactions.xml"> <xsl:for-each-group select="/account/transaction" group-adjacent="xs:date(@timestamp)"> <total date="{current-grouping-key()}" value="{sum(current-group()/@value)}"/> </xsl:for-each-group> </xsl:source-document> </out> </xsl:template>
The rules for xsl:source-document
say that the instruction is guaranteed-streamable if the contained sequence constructor is grounded, and the task
of streamability analysis is to prove that this is the case. As in the previous
example, we will take a short-cut by making the assumption that a sequence
constructor containing a single instruction can be replaced by that instruction in
the construct tree.
So the task is to show that the xsl:for-each-group
instruction is
grounded, which we can do as follows:
The relevant rules are to be found in 19.8.4.19 Streamability of xsl:for-each-group.
Note:
Rule numbers may be different in a version of the specification with change markings.
Rule 1 applies only if the select
expression is grounded. It is easy to see informally that this is not the
case (an expression that returns streamed nodes is never grounded). More
formally:
The select
expression is a path expression; the rules in
19.8.8.8 Streamability of Path Expressions apply.
The expression is rewritten as ((root(.) treat as
document-node())/child::account)/child::transaction
The left-hand operand (root(.) treat as
document-node())/child::account
is also a path expression,
so the rules in 19.8.8.8 Streamability of Path Expressions
apply recursively:
The left-hand operand root(.) treat as
document-node()
follows the rules for a
TreatExpr
in 19.8.8 Classifying Expressions; the proforma T treat
as TYPE
indicates that the general streamability rules apply with a single
operand having usage transmission.
This single operand root(.)
follows the rules in
19.8.9.18 Streamability of the root Function. The item type of the
operand .
is the context item type, which is the type established
by the xsl:source-document
instruction, namely
document-node()
. Under these conditions
root(.)
is rewritten as .
, so the
posture is the context posture established by the
xsl:source-document
instruction, namely striding. The sweep is
motionless.
The posture and sweep of
the expression root(.) treat as document-node()
are
the same as the posture and sweep of root(.)
, namely striding and motionless
The right-hand operand child::account
is governed
by the rules in 19.8.8.9 Streamability of Axis Steps.
The context posture is striding, and the axis is child
, so
the result posture is striding and the sweep
is consuming.
The posture of the path expression is the posture of the right-hand operand, that is striding, and its sweep is the wider sweep of the two operands, that is consuming
Returning to the outer path expression, the posture of the right hand operand child::transaction
is
striding, and its sweep is consuming.
So the posture of the select
expression as a whole is the posture of the right hand operand, that
is striding; and its sweep is the wider of the
sweeps of the operands, which is consuming.
Rule 2 does not apply: there is no group-by
attribute.
Rule 3 does not apply: there is a group-adjacent
attribute, but
it is motionless. The reasoning is as follows:
The value is a call to the constructor function xs:date
.
The rules in 19.8.8.14 Streamability of Static Function Calls apply.
There is a single operand, whose required type is atomic, so the
operand usage is absorption.
These rules refer to the general streamability rules, so we need to determine the context item type,
posture, and sweep of the
operand expression @timestamp
. This is done as
follows:
The expression is an AxisStep
, so the relevant
rules are in 19.8.8.9 Streamability of Axis Steps.
The context posture is the posture of the controlling operand of the focus-setting container, that is, is the
select
expression of the containing
xsl:for-each-group
instruction, which as
established above is striding. The context item type is similarly the inferred type
of the select
expression, and is
element()
.
Rules 1 and 2 do not apply because the context posture is striding.
Rule 3 does not apply because the attribute axis for an element node is not necessarily empty.
Rule 4 does not apply because there is no predicate.
So the sweep and posture
of the expression @timestamp
are given by the table
in Rule 5 as striding and motionless.
Returning to the general streamability rules for
the expression xs:date(@timestamp)
, the operand @timestamp
has U = absorption, T =
attribute()
, P = striding, S
= motionless.
Under Rule 1(b)(iii)(A), because T =
attribute()
, the operand usage
U′ becomes inspection.
Under Rule 1(b)(iii)(A), S′ = S = motionless.
Under Rule 2(e), the expression xs:date(@timestamp)
is
grounded and motionless.
Rule 4 (under xsl:for-each-group
) does not apply, because
there is no xsl:sort
child.
So Rule 5 applies. This relies on knowing the posture of
the sequence constructor contained in the
xsl:for-each-group
instruction: that is, the posture of the total
literal result element. This is calculated as
follows:
The rules that apply are in 19.8.4.1 Streamability of Literal Result Elements. The general streamability rules apply; there are two
operands, the attribute value templates
{current-grouping-key()}
and
{sum(current-group()/@value)}
, and in each case the
usage is absorption. We can simplify the analysis
by observing that the empty sequence constructor
contained in the literal result element can be ignored, since it is
grounded and motionless.
Consider first the operand {current-grouping-key()}
.
Section 19.8.7 Classifying Value Templates applies. This refers to
the general streamability rules; there is a
single operand, the expression
current-grouping-key()
, with usage absorption.
Section 19.8.9.5 Streamability of the current-grouping-key Function applies. This establishes that the expression is grounded and motionless.
It follows that the operand
{current-grouping-key()}
expression is also
grounded and motionless.
Now consider the operand
{sum(current-group()/@value)}
.
Section 19.8.7 Classifying Value Templates applies. This refers to the
general streamability rules; there is a single
operand, the expression sum(current-group()/@value)
, with
usage absorption.
The rules for the sum
function appear in 19.8.9 Classifying Calls to Built-In Functions. The proforma is given there
as fn:sum(A)
, which means that the general streamability rules apply, and that the single
operand current-group()/@value
has usage absorption. So we need to establish the posture, sweep, and type of this
expression, which we can do as follows:
The expression is a RelativePathExpr
, so section
19.8.8.8 Streamability of Path Expressions
applies.
The expression is expanded to
current-group()/attribute::value
.
The posture and sweep of
the left-hand operand current-group()
are defined
in 19.8.9.4 Streamability of the current-group Function. Since all
the required conditions are satisfied, the posture of current-group()
is the
posture of the select
expression, that is striding, and its
sweep is the sweep of
the select
expression, that is consuming.
The posture and sweep of
the right hand operand @value
are defined in
19.8.8.9 Streamability of Axis Steps. The context posture is the posture
of the left-hand operand current-group()
, namely
striding; the table in Rule 5 applies,
giving the result climbing and motionless
The posture of the
RelativePathExpr
is the posture of the right hand operand, namely striding. The sweep of the
RelativePathExpr
is the wider of the sweeps of its operands, which is
consuming
The type of the expression current-group()/@value
is determined using the rules in 19.1 Determining the Static Type of a Construct as
attribute()
.
So the sum
function has a single operand with
U = absorption, P =
striding, S = consuming,
T = attribute()
.
In the general streamability rules, Rule
1(b)(iii)(A) gives the adjusted usage as U′ = inspection, and Rule 1(b)(iii)(B) gives the adjusted
sweep as S′ = S = consuming.
Rule 2(d) gives the posture and sweep of the call to sum
as grounded and consuming.
So the literal result element has two operands, one of which is grounded and motionless, the other grounded and consuming. Rule 2(d) of the general streamability rules determines that the literal result element is grounded and consuming.
So the content of the xsl:source-document
instruction is grounded, which means that the instruction is guaranteed-streamable.
Certain constructs allow a stylesheet author to declare that a construct is streamable. Specifically:
Specifying streamable="yes"
on xsl:mode
declares
that all template rules in that mode (and all
template rules that specify mode="#all"
) are
streamable;
Specifying streamable="yes"
on
xsl:source-document
declares that its
contained sequence constructor is streamable;
Specifying streamable="yes"
on xsl:function
declares that the stylesheet function in question is
streamable;
Specifying streamable="yes"
on xsl:attribute-set
declares that the attribute set in question is streamable;
Specifying streamable="yes"
(explicitly or implicitly) on xsl:merge-source
declares
that the merging process is streamable with respect to that particular input.
Specifying streamable="yes"
on xsl:accumulator
declares that the accumulator can be evaluated on a streamed document.
[Definition: The above constructs (template rules belonging to a
mode declared with streamable="yes"
; and xsl:source-document
,
xsl:attribute-set
, xsl:function
,
xsl:merge-source
, and xsl:accumulator
elements specifying
streamable="yes"
) are said to be
declared-streamable.]
In each case the construct in question is said to be guaranteed-streamable if it satisfies two conditions:
The construct is declared-streamable.
Streamability analysis following the rules defined in this specification determines that streamed processing is possible (the detailed conditions vary from one construct to another).
[Definition: A guaranteed-streamable construct is a construct that is declared to be streamable and that follows the particular rules for that construct to make streaming possible, as defined by the analysis in this specification.]
For a streaming processor, that is, a processor that claims conformance with the streaming feature:
If a construct is guaranteed-streamable and the input is provided in streamable form, then the input must be processed using streaming.
Note:
The requirement to process the input using streaming does not apply if the processor is able to determine that this would convey no benefit: for example, if the input is supplied as a tree in memory. However, this does not remove the requirement to verify that the relevant stylesheet constructs are guaranteed-streamable.
If a construct is declared as streamable but is not guaranteed-streamable (that is, if it fails to satisfy the conditions for streamability defined in this specification), then the processor must be prepared to do any one of the following at user option:
Signal a static error [see ERR XTSE3430]
Process the stylesheet as if it were a non-streaming processor (see below)
Process the stylesheet with streaming if it is able to do so, or signal a static error [see ERR XTSE3430] if it is not able to do so.
[ERR XTSE3430] It is a static error if a package contains a construct that is declared to be streamable but which is not guaranteed-streamable, unless the user has indicated that the processor is to handle this situation by processing the stylesheet without streaming or by making use of processor extensions to the streamability rules where available.
For a non-streaming processor, the processor must evaluate the construct
delivering the same results as if execution used streaming, but with no constraints
on the evaluation strategy. (Processing may, of
course, fail due to insufficient memory being available, or for other reasons.)
A non-streaming processor is not
required to assess whether constructs are guaranteed-streamable, or to apply restrictions such as the rules
for where calls on the functions accumulator-before
and
accumulator-after
may appear. However, a non-streaming
processor must enforce the constraint implied by a
use-accumulators
attribute restricting which accumulators can be
used with a particular document.
Note:
This specification does not attempt to legislate precisely what constitutes evaluation “using streaming”. The most important test is that the amount of memory needed should be for practical purposes independent of the size of the source document, and in particular that the finite size of memory available should not impose a limit on the size of source document that can be processed.
The rules are designed to ensure that streaming processors can analyze streamability using rules different from those in this specification, provided that all constructs that are guaranteed-streamable according to this specification are actually streamable by the implementation. Furthermore, non-streaming processors are not required to analyze streamability at all.