19 Streamability

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:

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 concatFO30 function).

Operand roles have a number of properties used in the analysis:

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:

  1. If any of the operand postures is roaming, then the combined posture is roaming.

  2. If all of the operand postures are grounded, then the combined posture is grounded.

  3. If one or more of the operand postures is climbing and the remainder (if any) are grounded, then the combined posture is climbing.

  4. If one or more of the operand postures is striding and the remainder (if any) are grounded, then the combined posture is striding.

  5. 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.

  6. 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:

  1. 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.

  2. 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.

  3. [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.

  4. [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.

  5. 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.

19.1 Determining the Static Type of a 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:

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:

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.

Inferring a Static Type for XPath 3.0 Expressions
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:
  • If one or more of the arguments to the function have operand usage transmission, then the intersection of the U-type corresponding to the declared result type with the union of the static types of the arguments having usage transmission. (For example, the static type of the function call head(//text()) is U{text()}.)

  • Special rules apply to the current function: see 19.1.2 Static Type of a Call to current.

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.

19.1.1 Static Type of an Axis Step

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).

19.1.2 Static Type of a Call to current

The rules in this section define the static type of a call to the current function.

  1. 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.

  2. 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.

19.1.3 Schema-Aware Streamability Analysis

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.

19.2 Determining the Context Item Type

[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:

The context item type of a construct C is the first of the following that applies:

  1. 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.

  2. If the focus-setting container of C is an xsl:source-document instruction, then the context item type is U{document-node()}.

  3. 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.

  4. If the focus-setting container of C is a PredicatePattern, then the context item type is U{*}.

  5. 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".

  6. If the focus-setting container is any other declaration, for example xsl:key or xsl:accumulator, the context item type is U{*}.

  7. 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()}

19.3 Operand Roles

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:

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.

19.3.1 Examples showing the Effect of Operand Usage

Example: The Effect of Operand Usage on the Streamability of a Context Item Expression

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:

  1. The top-level construct is a sequence constructor. It is evaluated with a document node as the context item, and with a striding posture.

  2. The sequence constructor has one child instruction, which has an operand usage of transmission.

  3. The xsl:for-each instruction evaluates its select expression, with the context item and posture unchanged.

  4. 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.

  5. The same applies to the next step, child::emp

  6. The content of the xsl:for-each instruction is a sequence constructor which itself has a single operand, the xsl:value-of instruction.

  7. 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.

  8. The result of the trivial sequence constructor contained in the xsl:for-each instruction is therefore grounded and consuming

  9. The result of the xsl:for-each instruction (see 19.8.4.18 Streamability of xsl:for-each) is therefore grounded and consuming

  10. The result of the trivial sequence constructor contained in the xsl:source-document instruction is therefore grounded and consuming

  11. 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:

  1. The top-level construct is a sequence constructor. It is evaluated with a document node as the context item, and with a striding posture.

  2. The sequence constructor has one child instruction, which has an operand usage of transmission.

  3. The xsl:for-each instruction evaluates its select expression, with the context item and posture unchanged.

  4. 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.

  5. The same applies to the next step, child::emp

  6. The content of the xsl:for-each instruction is a sequence constructor which itself has a single operand, the xsl:sequence instruction.

  7. 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.

  8. The result of the trivial sequence constructor contained in the xsl:for-each instruction is therefore also striding and motionless.

  9. 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).

  10. The result of the trivial sequence constructor contained in the xsl:source-document instruction is therefore striding and consuming.

  11. 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.

 

Example: The Effect of Operand Roles on the Streamability of Path Expressions

Consider the expression .//chapter.

When this appears as an argument to the function countFO30 or existsFO30, 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 countFO30 or existsFO30) 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-joinFO30, 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-joinFO30 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-equalFO30 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.

19.4 Determining the Posture of a Construct

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:

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:

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.

19.5 Determining the Context Posture

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:

  1. 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.

  2. 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.

  3. If the focus-setting container of C is a template rule whose mode is declared with streamable="yes", then the context posture is striding.

  4. If the focus-setting container of C is a pattern, then the context posture is striding.

  5. If the focus-setting container of C is an xsl:attribute-set declaration with the attribute streamable="yes", then the context posture is striding.

  6. 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.

  7. Otherwise, the context posture is the posture of the controlling operand of the focus-setting container of C.

19.6 The Sweep of a Construct

[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.

Combinations of Sweep and Posture
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.

19.7 Grounded Consuming Constructs

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:

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 lastFO30 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 lastFO30 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 lastFO30 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 positionFO30 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.

19.8 Classifying Constructs

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:

19.8.1 General Rules for Streamability

[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 docFO30 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:

  1. For each operand of C:

    1. Establish:

      1. 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()}.

      2. The sweep S and posture P of the operand (by applying the rules in this section 19.8 Classifying Constructs to that operand, recursively).

      3. The operand usage U corresponding to the role of the operand within C (from the information in this section 19.8 Classifying Constructs).

    2. Compute the adjusted sweep S′ of the operand by taking the first of the following that applies:

      1. 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.)

      2. If P is grounded, then S′ is S.

      3. Otherwise (P is not grounded, which implies that the operand is capable of returning streamed nodes), compute S′ as follows:

        1. Compute the adjusted usage U′ as follows:

          1. 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.

          2. Otherwise, U′ is U.

        2. Compute the adjusted sweep S′ from the table below:

          Computing the Adjusted Sweep of an Expression
          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
    3. [Definition: An operand is potentially consuming if at least one of the following conditions applies:

      1. The operand’s adjusted sweep S′ is consuming.

      2. The operand usage is transmission and the operand is not grounded.

      ]

  2. 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:

    1. If C has no operands, then grounded and motionless.

    2. If any operand o has an adjusted sweep S′(o) of free-ranging, then roaming and free-ranging.

    3. If more than one operand is potentially consuming, then:

      1. 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

      2. 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.

      3. Otherwise, roaming and free-ranging.

    4. If exactly one operand o is potentially consuming, then:

      1. If o is a higher-order operand of C, then roaming and free-ranging.

      2. If the operand usage of o is absorption or inspection, then grounded and consuming.

      3. 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 headFO30, exactly-oneFO30, and zero-or-oneFO30. 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.

      4. Otherwise (the operand usage of o is transmission), the posture and adjusted sweep of o.

    5. 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.

19.8.2 Examples of the General Streamability Rules

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 countFO30 is crawling and consuming. The countFO30 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.)

19.8.3 Classifying Sequence Constructors

The posture and sweep of a sequence constructor are determined by the general streamability rules.

The operand roles and their usages are:

  1. 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.

  2. 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:

  1. An empty sequence constructor is motionless, and its posture is grounded.

  2. 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.)

  3. Informally, a sequence constructor is not streamable if it contains more than one instruction that moves the position of the input stream.

  4. 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.

19.8.4 Classifying Instructions

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.

19.8.4.1 Streamability of Literal Result Elements

The posture and sweep of a literal result element follow the general streamability rules. The operand roles and their usages are:

  1. The contained sequence constructor (usage absorption)

  2. Any expressions contained in attribute value templates among the literal result element’s attributes (usage absorption)

  3. 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.

19.8.4.2 Streamability of extension instructions

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:

  1. 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.

19.8.4.3 Streamability of xsl:analyze-string

The posture and sweep of xsl:analyze-string follow the general streamability rules. The operand roles and their usages are:

  1. the select expression (usage absorption);

  2. the regex attribute value template (usage absorption);

  3. 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.

19.8.4.4 Streamability of 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:

  1. An implicit operand: a context item expression (.), with usage absorption;

  2. 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.

Note:

The instruction will normally be grounded and consuming, provided that nodes in a streamed document are not passed as parameters to the called template rule.

19.8.4.5 Streamability of 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:

  1. 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:

    1. The select expression (the operand usage is irrelevant, but can be taken as absorption)

    2. 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()*)

    3. Any attribute value templates appearing in attributes of a child xsl:sort instruction (usage absorption)

    4. 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.

  2. If there is an xsl:sort child element, then roaming and free-ranging.

  3. 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.

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

  5. 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:

    1. The (explicit or implicit) select expression, with usage absorption;

    2. 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.

19.8.4.6 Streamability of xsl:assert

The posture and sweep of xsl:assert follow the general streamability rules. The operand roles and their usages are as follows:

  1. The test expression (usage inspection)

  2. The select expression (usage absorption)

  3. The error-code attribute value template (usage absorption)

  4. The contained sequence constructor (usage absorption).

19.8.4.7 Streamability of xsl:attribute

The posture and sweep of xsl:attribute follow the general streamability rules. The operand roles and their usages are as follows:

  1. The name attribute value template (usage absorption)

  2. The namespace attribute value template (usage absorption)

  3. The select expression (usage absorption)

  4. The separator attribute value template (usage absorption)

  5. The contained sequence constructor (usage absorption).

19.8.4.8 Streamability of xsl:break

The posture and sweep of xsl:break follow the general streamability rules. The operand roles and their usages are as follows:

  1. The select expression (usage transmission)

  2. The contained sequence constructor (usage transmission).

19.8.4.9 Streamability of 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:

  1. 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.

  2. 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.

19.8.4.10 Streamability of xsl:choose

The posture and sweep of xsl:choose follow the general streamability rules. The operand roles and their usages are as follows:

  1. The test attribute of contained xsl:when elements (usage inspection).

  2. 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:

  1. 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.

  2. 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.

19.8.4.11 Streamability of xsl:comment

The posture and sweep of xsl:comment follow the general streamability rules. The operand roles and their usages are as follows:

  1. The select expression (usage absorption)

  2. The contained sequence constructor (usage absorption).

19.8.4.12 Streamability of xsl:copy

The posture and sweep of xsl:copy follow the general streamability rules. The operand roles and their usages are as follows:

  1. The expression in the select attribute, defaulting to a context item expression (.) (usage inspection)

  2. 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.

  3. 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>
19.8.4.13 Streamability of 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:

  1. The select expression (usage absorption).

19.8.4.14 Streamability of xsl:document

The posture and sweep of xsl:document follow the general streamability rules. The operand roles and their usages are as follows:

  1. The contained sequence constructor (usage absorption).

19.8.4.15 Streamability of xsl:element

The posture and sweep of xsl:element follow the general streamability rules. The operand roles and their usages are as follows:

  1. The name attribute value template (usage absorption)

  2. The namespace attribute value template (usage absorption)

  3. 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.

  4. The contained sequence constructor (usage absorption).

19.8.4.16 Streamability of xsl:evaluate

The posture and sweep of xsl:evaluate follow the general streamability rules. The operand roles and their usages are as follows:

  1. The xpath expression (usage absorption)

  2. The context-item expression (usage navigation)

  3. The with-params expression (usage navigation)

  4. The base-uri attribute value template (usage absorption)

  5. The namespace-context expression (usage inspection)

  6. The schema-aware attribute value template (usage absorption)

  7. 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.

19.8.4.17 Streamability of 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.

19.8.4.18 Streamability of xsl:for-each

The posture and sweep of the xsl:for-each instruction are the first of the following that applies:

  1. 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:

    1. The select expression (the operand usage is irrelevant, but can be taken as inspection)

    2. The contained sequence constructor (usage transmission). This is a higher-order operand; its context posture is grounded.

    3. Any attribute value templates appearing in attributes of a child xsl:sort instruction (usage absorption)

    4. 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.

  2. If there is an xsl:sort child element, then roaming and free-ranging.

  3. If the posture of the select expression is crawling and the sweep of the contained sequence constructor is consuming, then roaming and free-ranging.

  4. Otherwise:

    1. 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.

    2. 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.

19.8.4.19 Streamability of xsl:for-each-group

The posture and sweep of the xsl:for-each-group instruction are the first of the following that applies:

  1. 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:

    1. The select expression (the operand usage is irrelevant, but can be taken as inspection)

    2. The collation attribute value template (usage absorption)

    3. Any attribute value templates appearing in attributes of a child xsl:sort instruction (usage absorption)

    4. The group-by or group-adjacent expression, assessed with a context posture of grounded (usage absorption).

    5. The select expression or contained sequence constructor of any xsl:sort children, assessed with a context posture of grounded (usage absorption).

    6. The group-starting-with or group-ending-with patterns if present; these are higher-order operands with usage inspection.

  2. If there is a group-by attribute and the instruction is not a child of xsl:fork, then roaming and free-ranging.

  3. If there is a group-by or group-adjacent attribute that is not motionless, then roaming and free-ranging.

  4. If there is an xsl:sort child element and the instruction is not a child of xsl:fork, then roaming and free-ranging.

  5. If the posture of the select expression is crawling and the sweep of the contained sequence constructor is consuming, then roaming and free-ranging.

  6. Otherwise:

    1. 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.

    2. 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.

19.8.4.20 Streamability of xsl:fork

The posture and sweep of xsl:fork are the first of the following that applies:

  1. If there is a child xsl:for-each-group instruction, then the posture and the sweep of that instruction.

  2. If there are no child xsl:sequence instructions (other than xsl:fallback), then grounded and motionless.

  3. If there is a child xsl:sequence instruction whose posture is not grounded, then roaming and free-ranging.

  4. 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>
19.8.4.21 Streamability of xsl:if

The posture and sweep of xsl:if follow the general streamability rules. The operand roles and their usages are as follows:

  1. The test expression (usage inspection)

  2. The contained sequence constructor (usage transmission).

19.8.4.22 Streamability of xsl:iterate

The posture and sweep of the xsl:iterate instruction are the first of the following that applies:

  1. 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:

    1. The select expression (the operand usage is irrelevant, but can be taken as inspection)

    2. The select expression or contained sequence constructor of any xsl:param children (usage navigation)

    3. 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)

    4. 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.

  2. If there is an xsl:param child whose initializing select expression or sequence constructor is not grounded and motionless, then roaming and free-ranging.

  3. If there is an xsl:on-completion child whose select expression or sequence constructor is not grounded and motionless, then roaming and free-ranging.

  4. If the posture of the select expression is crawling and the sweep of the contained sequence constructor is consuming, then roaming and free-ranging.

  5. Otherwise:

    1. 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.

    2. 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.

19.8.4.23 Streamability of xsl:map

The posture and sweep of the xsl:map instruction are determined by the first of the following that applies:

  1. If the sequence constructor within the instruction consists exclusively of xsl:map-entry instructions (and xsl:fallback instructions, which are ignored), then:

    1. If any of these xsl:map-entry children is roaming or free-ranging, then roaming and free-ranging;

    2. Otherwise, grounded and the widest sweep of the xsl:map-entry children.

  2. 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.

19.8.4.24 Streamability of 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:

  1. The key expression (usage absorption)

  2. The select expression (usage navigation)

    Note:

    This effectively means that the select expression must not return nodes from a streamed input document.

  3. The contained sequence constructor (usage navigation).

19.8.4.25 Streamability of 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:

  1. If every xsl:merge-source child element satisfies all the following conditions:

    1. The expression in the for-each-item attribute is either absent, or grounded and motionless;

    2. The expression in the for-each-source attribute is either absent, or grounded and motionless;

    3. 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.

  2. Otherwise, the xsl:merge instruction roaming and free-ranging.

19.8.4.26 Streamability of xsl:message

The posture and sweep of xsl:message follow the general streamability rules. The operand roles and their usages are as follows:

  1. The select expression (usage absorption)

  2. The terminate attribute value template (usage absorption)

  3. The error-code attribute value template (usage absorption)

  4. The contained sequence constructor (usage absorption).

19.8.4.27 Streamability of xsl:namespace

The posture and sweep of xsl:namespace follow the general streamability rules. The operand roles and their usages are as follows:

  1. The name attribute value template (usage absorption)

  2. The select expression (usage absorption)

  3. The contained sequence constructor (usage absorption).

19.8.4.28 Streamability of 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:

  1. 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.

19.8.4.29 Streamability of xsl:next-match

The rules are the same as for xsl:apply-imports: see 19.8.4.4 Streamability of xsl:apply-imports.

19.8.4.30 Streamability of xsl:number

The posture and sweep of xsl:number follow the general streamability rules. The operand roles and their usages are as follows:

  1. The value attribute if present: usage absorption

  2. The select attribute if there is no value attribute, defaulting to the context item expression (.) if the select attribute is also absent: usage navigation

  3. The attribute value templates in the format, lang, letter-value, ordinal, start-at, grouping-separator, and grouping-size attributes (usage absorption)

  4. 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.

19.8.4.31 Streamability of 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.

19.8.4.32 Streamability of 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.

19.8.4.33 Streamability of 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:

  1. The expression in the select attribute: usage navigation (because order is not preserved)

  2. The expressions in the attribute value templates of xsl:sort child elements: usage absorption

  3. 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.

19.8.4.34 Streamability of 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:

  1. The name attribute value template (usage absorption)

  2. The select expression (usage absorption)

  3. The contained sequence constructor (usage absorption).

19.8.4.35 Streamability of 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:

  1. The href attribute value template (usage absorption)

  2. The attribute value templates containing serialization properties (usage absorption)

  3. The contained sequence constructor (usage absorption).

19.8.4.36 Streamability of xsl:sequence

The posture and sweep of xsl:sequence follow the general streamability rules. The operand roles and their usages are as follows:

  1. The select attribute value template (usage transmission)

  2. The contained sequence constructor (usage transmission).

19.8.4.37 Streamability of 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:

  1. 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.

  2. 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.

  3. Otherwise, the posture is grounded and the sweep is the sweep of the href attribute value template.

19.8.4.38 Streamability of 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.

19.8.4.39 Streamability of xsl:try

The posture and sweep of the xsl:try instruction follow the general streamability rules. The operand roles and usages are as follows:

  1. 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.)

  2. The select expressions and/or contained sequence constructor of the xsl:catch child elements. These form a choice operand group with operand usage transmission.

Note:

The overall effect of these rules is that either the xsl:try branch or the xsl:catch branch may consume the streamed input, but not both. If there is more than one xsl:catch branch then they may all consume the input, since only one of these branches can be evaluated.

19.8.4.40 Streamability of 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:

  1. The select expression (usage absorption)

  2. The separator attribute value template (usage absorption)

  3. The contained sequence constructor (usage absorption).

19.8.4.41 Streamability of 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:

  1. If there is an as attribute, then:

    1. The select expression (with type-determined usage based on the as attribute).

    2. The contained sequence constructor (with type-determined usage based on the as attribute).

  2. If there is no as attribute, then:

    1. The select expression (usage navigation).

    2. 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.

19.8.4.42 Streamability of xsl:where-populated

The posture and sweep of an xsl:where-populated instruction are the posture and sweep of the contained sequence constructor.

19.8.5 Classifying Stylesheet Functions

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:

  1. The stylesheet function is declared-streamable, and the argument in question is the first argument of the function call.

  2. 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.

19.8.5.1 Streamability Category: unclassified

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.

Example: An unclassified stylesheet function that accepts nodes

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).

 

Example: An unclassified stylesheet function that accepts atomic values

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.

19.8.5.2 Streamability Category: absorbing

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.

Example: An absorbing stylesheet function

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.

 

Example: An absorbing stylesheet function with two arguments

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.

 

Example: A recursive absorbing stylesheet function

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.

19.8.5.3 Streamability Category: inspection

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.

Example: Example of an inspection stylesheet function

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.

 

Example: Example of an inspection stylesheet function with two arguments

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.

19.8.5.4 Streamability Category: filter

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.

Example: Example of a filtering stylesheet function

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.

19.8.5.5 Streamability Category: shallow-descent

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:

  1. Let T0 be the U-type corresponding to the declared type of the streaming parameter in the function signature (defaulting to U{*}).

  2. Let P0 and S0 be the type-adjusted posture and sweep of the first argument expression, based on type T0.

  3. If P0 is not striding or grounded, the function call is roaming and free-ranging.

  4. 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.

  5. If P1 is not grounded, the function call is roaming and free-ranging.

  6. If S0 and S1 are both consuming, or if either is free-ranging, then the function call is roaming and free-ranging.

  7. 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.

  8. Otherwise, the posture of the function call is P0, and the sweep of the function call is as follows:

    1. 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.

    2. 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.

    3. Otherwise, consuming.

Example: A shallow-descent stylesheet function

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.

19.8.5.6 Streamability Category: deep-descent

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:

  1. Let T0 be the U-type corresponding to the declared type of the streaming parameter in the function signature (defaulting to U{*}).

  2. Let P0 and S0 be the type-adjusted posture and sweep of the first argument expression, based on type T0.

  3. If P0 is not striding or grounded, the function call is roaming and free-ranging.

  4. 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.

  5. If P1 is not grounded, the function call is roaming and free-ranging.

  6. If S0 and S1 are both consuming, or if either is free-ranging, the function call is roaming and free-ranging.

  7. 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.

  8. Otherwise, the posture of the function call is crawling, and the sweep of the function call is as follows:

    1. 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.

    2. 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.

    3. Otherwise, consuming.

Example: A deep-descent stylesheet function

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.

19.8.5.7 Streamability Category: ascent

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:

  1. 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.

  2. If P0 is roaming or S0 is free-ranging, then the function call is roaming and free-ranging.

  3. If S0 is not motionless, then the function call is roaming and free-ranging.

  4. If P0 is roaming, then the function call is roaming and free-ranging.

  5. If P0 is grounded, then the function call is grounded and motionless.

  6. Otherwise, the function call is climbing and motionless.

Example: An ascending stylesheet function

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.

19.8.6 Classifying Attribute Sets

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:

  1. 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.

  2. 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.

19.8.7 Classifying Value Templates

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.

19.8.8 Classifying Expressions

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 (QP) 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.

Operand Roles for XPath Expressions
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:

  1. 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-idFO30 function: let $x := generate-id(.) return descendant::x[generate-id(ancestor::y[1]) = $x]

19.8.8.1 Streamability of for Expressions

Writing 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:

  1. If S is not grounded, then roaming and free-ranging.

  2. Otherwise, the general streamability rules apply. The operand roles are:

    1. The in expression (S). This has usage navigation.

    2. 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]).

19.8.8.2 Streamability of Quantified Expressions

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:

  1. The in expression (S). This has usage navigation.

  2. 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.

19.8.8.3 Streamability of if expressions

Writing 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.

19.8.8.4 Streamability of union, intersect, and except Expressions

The posture and sweep are the first of the following that applies:

  1. If either of the two operands is free-ranging, then roaming and free-ranging (Example: . | following-sibling::*).

  2. If either of the two operands is grounded and motionless, then the posture and sweep of the other operand (Example: . | doc('abc.com')//x)

  3. If both operands are climbing, then climbing and and the wider of the sweeps of the two operands (Example: parent::A | */ancestor::B).

  4. 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: * | */*).

  5. 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.

19.8.8.5 Streamability of instance of Expressions

For 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:

  1. If the ItemType of ST is a DocumentTest, optionally parenthesized, that contains an ElementTest or SchemaElementTest then absorption

  2. 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 nameFO30 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.

19.8.8.6 Streamability of treat as Expressions

For 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:

  1. If the ItemType of ST is a DocumentTest, optionally parenthesized, that contains an ElementTest or SchemaElementTest then roaming and free-ranging.

  2. 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.

19.8.8.7 Streamability of Simple Mapping Expressions

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.

19.8.8.8 Streamability of Path Expressions

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 rootFO30, 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 posture of a relative path expression is assessed in two phases, as follows:

  1. 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.

  2. If the provisional posture is roaming, then it is reassessed as follows:

    1. [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.

    2. If the expression is a scanning expression then:

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

      2. Otherwise, its posture is striding

  3. 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.

19.8.8.9 Streamability of Axis Steps

The sweep and posture of an AxisStep S are determined by the first of the following rules that applies:

  1. If the context posture is grounded, then the sweep is motionless and the posture is grounded;

  2. If the context posture is roaming, then the sweep is free-ranging and the posture is roaming;

  3. 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);

  4. If all the following conditions are satisfied:

    1. The context posture is striding

    2. The axis is descendant or descendant-or-self

    3. There is a predicate P in the PredicateList that satisfies all the following conditions:

      1. The static type of P is a subtype of U{xs:decimal, xs:double, xs:float}

      2. 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;

    then striding and consuming

    Note:

    Examples are descendant::section[1], descendant::section[$i+1], descendant::section[count($x)]. The significance of this rule is that it detects cases where the descendant axis selects a singleton, and where the posture of the result can therefore be striding rather than crawling.

  5. If the PredicateList contains a Predicate that is not motionless, then the sweep is free-ranging and the posture is roaming;

  6. 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()}.

    Streamability of Axis Steps Based on Context Posture
    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.

19.8.8.10 Streamability of Filter Expressions

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:

  1. If all the following conditions are satisfied:

    1. B is crawling;

    2. The static type of P is a subtype of U{xs:decimal, xs:double, xs:float}, and

    3. 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.

  2. 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.

  3. 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.

19.8.8.11 Streamability of Dynamic Function Calls

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:

  1. The base expression that computes the function value itself (here $F). This has usage inspection.

  2. 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 (?).

19.8.8.12 Streamability of Variable References

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.

19.8.8.13 Streamability of the Context Item Expression

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 dataFO30 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.

19.8.8.14 Streamability of Static Function Calls

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:

  1. If the function is focus-dependent and the context posture is not grounded, then the function call is roaming and free-ranging.

  2. 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.

  3. If the target is an extension function, the posture and sweep are implementation-defined.

  4. 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.

19.8.8.15 Streamability of Named Function References

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.

19.8.8.16 Streamability of Inline Function Declarations

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.

19.8.8.17 Streamability of Map Constructors

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.

19.8.8.18 Streamability of Lookup Expressions

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:

  1. In the wildcard form of the expression, E?*, there is only one operand, E. This has operand usage inspection.

  2. Where the construct K is an NCName, the expression E?NAME is treated as equivalent to E?("NAME").

  3. Where the construct K is an integer, the expression E?N is treated as equivalent to E?(N).

  4. 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.

19.8.9 Classifying Calls to Built-In Functions

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)

19.8.9.1 Streamability of the accumulator-after Function

See 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:

  1. If the first argument (the accumulator name) is not motionless, the function is free-ranging.

  2. If the context posture is grounded, the function is motionless.

  3. 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.

  4. 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.

  5. 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.

  6. 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.

  7. 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.

  8. 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.)

  9. Otherwise, the function call is motionless.

Note:

The following notes apply to the above rules with matching numbers:

  1. 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.

  2. If the context posture is grounded, then the target of the accumulator is not a streamed node, so no streaming restrictions apply.

  3. 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.

  4. 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.

  5. 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].

  6. 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).

  7. 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.

  8. 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.

  9. 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.

19.8.9.2 Streamability of the accumulator-before Function

See also 18.2.9 Streamability of Accumulators.

The posture and sweep of the function call are assessed as follows:

  1. If the argument to accumulator-before is motionless, the function call is grounded and motionless.

  2. Otherwise, the function call is roaming and free-ranging.

19.8.9.3 Streamability of the current Function

The sweep and posture of a call to the current function are determined as follows:

  1. 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.

  2. Otherwise, let E be the outermost containing XPath expression of the call to the current function.

  3. If the context posture of E is grounded, then motionless and grounded.

  4. 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].

  5. Otherwise, the posture is the context posture, and the sweep is motionless.

19.8.9.4 Streamability of the current-group Function

The sweep and posture of a call C to the current-group function are as follows:

  1. If all the following conditions are true:

    1. C has a containing xsl:for-each-group instruction (call it F)

    2. 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

    3. 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.

  2. 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.

19.8.9.5 Streamability of the current-grouping-key Function

A call to the current-grouping-key function is grounded and motionless.

19.8.9.6 Streamability of the current-merge-group Function

A 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.

19.8.9.7 Streamability of the current-merge-key Function

A call to the current-merge-key function is grounded and motionless.

19.8.9.8 Streamability of the fold-leftFO30 Function

The 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.

19.8.9.9 Streamability of the fold-rightFO30 Function

The 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 reverseFO30 function: see 19.8.9.17 Streamability of the reverse Function.

19.8.9.10 Streamability of the for-eachFO30 Function

The 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 filterFO30 function is streamable if either (a) the supplied sequence is grounded, or (b) the supplied function is statically known to atomize its argument.

19.8.9.11 Streamability of the for-each-pairFO30 Function

The function call for-each($seq1, $seq2, $f), follows the general streamability rules, where:

  1. The first argument $seq1 has type-determined usage based on the type of the first argument of the function supplied as $f.

  2. 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-pairFO30 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.

19.8.9.12 Streamability of the function-lookupFO30 Function

See 10.3.6 Dynamic Access to Functions for special rules that relate to streamability of calls to the function-lookupFO30 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.

19.8.9.13 Streamability of the innermostFO30 Function

The 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 innermostFO30 until all its descendants have been read.

19.8.9.14 Streamability of the lastFO30 Function

If the context posture for a call on the lastFO30 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 lastFO30 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 lastFO30 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.

19.8.9.15 Streamability of the outermostFO30 Function

The 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 innermostFO30 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.

19.8.9.16 Streamability of the positionFO30 Function

The positionFO30 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 positionFO30 function.

It does have special treatment within a predicate of a pattern, however: a pattern is not motionless if it contains a call to positionFO30, as explained in 19.8.10 Classifying Patterns.

19.8.9.17 Streamability of the reverseFO30 Function

The reverseFO30 function follows the general streamability rules, with its operand classified as having operand usage navigation.

Note:

This means in effect that a call on reverseFO30 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())

19.8.9.18 Streamability of the rootFO30 Function

The 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 rootFO30 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.

19.8.10 Classifying Patterns

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:

  1. The pattern does not contain a RootedPath.

  2. If the pattern contains predicates, then every top-level Predicate in the pattern satisfies all the following conditions:

    1. 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.

    2. 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.

  3. 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:

  1. 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:

    1. positionFO30

    2. lastFO30

    3. function-lookupFO30.

    Note:

    The exception for nested predicates is there to ensure that patterns such as match="p[@code = $status[last()]] are not disqualified.

  2. 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())

19.9 Examples of Streamability Analysis

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.

Example: A recursive-descent template rule

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:

  1. The match pattern must be motionless.

  2. The body of the template rule must be grounded.

  3. 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:

  1. 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.

  2. 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:

    1. 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.

    2. 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.

    3. 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.

      1. The sequence constructor has a single operand (the xsl:apply-templates instruction); again U = transmission, T = U{*}.

      2. The posture P and sweep S of the xsl:apply-templates instruction are established as follows:

        1. The rules that apply are in 19.8.4.5 Streamability of xsl:apply-templates.

        2. 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:

          1. The context posture of the axis step is established by the template rule as a whole, as striding.

          2. Therefore rules 1 and 2 do not apply.

          3. 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.

          4. Rule 4 does not apply because there are no predicates.

          5. 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.

          6. So the select expression is not grounded. (The same result can be reached intuitively: an expression that selects streamed nodes will never be grounded.)

        3. Rule 2 does not apply because there is no xsl:sort element.

        4. Rule 3 does not apply because the mode is declared with streamable="yes".

        5. So the posture P and sweep S of the xsl:apply-templates instruction are established by the general streamability rules, as follows:

          1. There is a single operand, the implicit select="child::node()" expression, with usage U = absorption.

          2. We have already established that for this operand, the posture P = striding and the sweep S = consuming.

          3. By the rules in 19.1 Determining the Static Type of a Construct, the type T of the select expression is node().

          4. In the general streamability rules, the adjusted sweep S′ for an operand with (P = striding, U = absorption) is consuming,

          5. Rule 2(d) then applies, so the xsl:apply-templates instruction is consuming and grounded.

      3. 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.

    4. 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.

  3. 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.

  4. 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.

 

Example: An aggregating template rule

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:

  1. The match pattern must be motionless.

  2. The body of the template rule must be grounded.

  3. 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:

  1. First establish that that the expression @currency='USD' is motionless, as follows:

    1. The predicate is a general comparison (GeneralComp) which follows the general streamability rules.

    2. There are two operands: an AxisStep with a defaulted ForwardAxis, and a Literal. Both operand roles are absorption.

    3. 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.

    4. The right-hand operand, being a literal, is grounded and motionless.

    5. In the general streamability rules, rule 2(e) applies, so the predicate is grounded and motionless

  2. Now establish that that the expression @currency='USD' is non-positional, as follows:

    1. Rule 1 is satisfied: the predicate does not call positionFO30, lastFO30, or function-lookupFO30.

    2. 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.

  1. We need to show that the <total> literal result element is grounded.

  2. The rules that apply are in 19.8.4.1 Streamability of Literal Result Elements.

  3. 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().

  4. So we need to determine the posture and sweep of the xsl:value-of instruction.

    1. The rules are given in 19.8.4.40 Streamability of xsl:value-of.

    2. The general streamability rules apply. There is one operand, the expression sum(transaction/@value), which has operand usage U = absorption.

    3. The type T of this operand is the return type defined in the signature of the sumFO30 function, that is, xs:anyAtomicType.

    4. The posture P and sweep S are established as follows:

      1. The rules that apply to the call on sumFO30 are given in 19.8.9 Classifying Calls to Built-In Functions.

      2. 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.

      3. 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().

      4. 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:

        1. The expression is expanded to child::transaction/attribute::value.

        2. 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:

          1. The context posture is striding, because the focus-setting container is the template rule itself.

          2. The context item type is element(), based on the match type of the pattern match="transactions[@currency='USD']".

          3. Rules 1 and 2 do not apply because the context posture is striding.

          4. Rule 3 does not apply because the child axis applied to an element node is not necessarily empty.

          5. Rule 4 does not apply because there are no predicates.

          6. Rule 5 applies, and the table entry with context posture = striding, axis = child gives a result posture of striding and a sweep of consuming.

        3. 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:

          1. The context posture, as we have seen, is striding.

          2. The context item type is element(), based on the type of the left-hand operand child::transaction.

          3. Rules 1 and 2 do not apply because the context posture is striding.

          4. Rule 3 does not apply because the attribute axis applied to an element node is not necessarily empty.

          5. Rule 4 does not apply because there are no predicates.

          6. Rule 5 applies, and the table entry with context posture = striding, axis = attribute gives a result posture of striding and a sweep of motionless.

        4. The posture of the relative path expression child::transaction/attribute::value is therefore striding.

        5. 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.

      5. So the first and only operand to the call on sum() has U = absorption, T = attribute(), P = climbing, and S = consuming

      6. 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.

      7. Rule 2(d) now applies, so the call on sum() is grounded and consuming.

    5. 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.

  5. 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.

  6. Therefore the body of the template rule is grounded, and since the other conditions are also satisfied, it is guaranteed-streamable.

 

Example: Streamed Grouping

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:

  1. 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.

  2. 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:

    1. The select expression is a path expression; the rules in 19.8.8.8 Streamability of Path Expressions apply.

    2. The expression is rewritten as ((root(.) treat as document-node())/child::account)/child::transaction

    3. 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:

      1. 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.

      2. 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.

      3. 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

      4. 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.

      5. 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

    4. Returning to the outer path expression, the posture of the right hand operand child::transaction is striding, and its sweep is consuming.

    5. 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.

  3. Rule 2 does not apply: there is no group-by attribute.

  4. Rule 3 does not apply: there is a group-adjacent attribute, but it is motionless. The reasoning is as follows:

    1. 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.

    2. 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:

      1. The expression is an AxisStep, so the relevant rules are in 19.8.8.9 Streamability of Axis Steps.

      2. 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().

      3. Rules 1 and 2 do not apply because the context posture is striding.

      4. Rule 3 does not apply because the attribute axis for an element node is not necessarily empty.

      5. Rule 4 does not apply because there is no predicate.

      6. So the sweep and posture of the expression @timestamp are given by the table in Rule 5 as striding and motionless.

    3. Returning to the general streamability rules for the expression xs:date(@timestamp), the operand @timestamp has U = absorption, T = attribute(), P = striding, S = motionless.

    4. Under Rule 1(b)(iii)(A), because T = attribute(), the operand usage U′ becomes inspection.

    5. Under Rule 1(b)(iii)(A), S′ = S = motionless.

    6. Under Rule 2(e), the expression xs:date(@timestamp) is grounded and motionless.

  5. Rule 4 (under xsl:for-each-group) does not apply, because there is no xsl:sort child.

  6. 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:

    1. 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.

    2. Consider first the operand {current-grouping-key()}.

      1. 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.

      2. Section 19.8.9.5 Streamability of the current-grouping-key Function applies. This establishes that the expression is grounded and motionless.

      3. It follows that the operand {current-grouping-key()} expression is also grounded and motionless.

    3. Now consider the operand {sum(current-group()/@value)}.

    4. 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.

    5. 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:

      1. The expression is a RelativePathExpr, so section 19.8.8.8 Streamability of Path Expressions applies.

      2. The expression is expanded to current-group()/attribute::value.

      3. 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.

      4. 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

      5. 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

      6. 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().

    6. So the sum function has a single operand with U = absorption, P = striding, S = consuming, T = attribute().

    7. 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.

  7. 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.

  8. So the content of the xsl:source-document instruction is grounded, which means that the instruction is guaranteed-streamable.

19.10 Streamability Guarantees

Certain constructs allow a stylesheet author to declare that a construct is streamable. Specifically:

[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:

  1. The construct is declared-streamable.

  2. 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:

  1. 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.

  2. 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:

    1. Signal a static error [see ERR XTSE3430]

    2. Process the stylesheet as if it were a non-streaming processor (see below)

    3. 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.