View Old View New View Both View Only Previous Next

This draft contains only sections that have differences from the version that it modified.

W3C

XSL Transformations (XSLT) Version 4.0

W3C Editor's Draft 23 February 2026

This version:
https://qt4cg.org/specifications/xslt-40/
Latest version:
https://qt4cg.org/specifications/xslt-40/
Most recent Recommendation of XSL Transformations (XSLT):
https://www.w3.org/TR/xslt-30/
Editor:
Michael Kay, Saxonica <http://www.saxonica.com/>

The following associated resources are available: Specification in XML format, XSD 1.1 Schema for XSLT 4.0 Stylesheets (non-normative), Relax-NG Schema for XSLT 4.0 Stylesheets (non-normative), Stylesheet for XML-to-JSON conversion (non-normative)


Abstract

This specification defines the syntax and semantics of XSLT 4.0, a language designed primarily for transforming XML documents into other XML documents.

XSLT 4.0 is a revised version of the XSLT 3.0 Recommendation [XSLT 3.0] published on 8 June 2017. Changes are presented in 1.2 What’s New in XSLT 4.0?.

XSLT 4.0 is designed to be used in conjunction with XPath 4.0, which is defined in [XPath 4.0]. XSLT shares the same data model as XPath 4.0, which is defined in [XDM 4.0], and it uses the library of functions and operators defined in [Functions and Operators 4.0]. XPath 4.0 and the underlying function library introduce a number of enhancements, for example the availability of union and record types.

This document contains hyperlinks to specific sections or definitions within other documents in this family of specifications. These links are indicated visually by a superscript identifying the target specification: for example XP for XPath 4.0, DM for the XDM data model version 4.0, FO for Functions and Operators version 4.0.

Status of this Document

This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at https://www.w3.org/TR/.

This document has no official standing. It is produced by the editor as a proposal for community review. Insofar as it copies large amounts of text from the W3C XSLT 3.0 Recommendation, W3C copyright and similar provisions apply.

Dedication

The publications of this community group are dedicated to our co-chair, Michael Sperberg-McQueen (1954–2024).


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 concat 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 fn(*) 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 coercion 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 coercion 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.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:

  • [Definition: Grounded: indicates that the value returned by the construct does not contain nodes from the streamed input document]. Atomic items and function items are always grounded; nodes are grounded if it is known that they are in a non-streamed document. For example the expressions doc('x') and copy-of(.) both return grounded nodes.

  • [Definition: Climbing: indicates that streamed nodes returned by the construct are reached by navigating the parent, ancestor[-or-self], attribute, and/or namespace axes from the node at the current streaming position.] When the context posture is climbing, use of certain axes such as parent and ancestor is permitted, but use of other axes such as child or descendant violates the streamability rules.

  • [Definition: Crawling: typically indicates that streamed nodes returned by a construct are reached by navigating the descendant[-or-self] axis.] Nodes reached in this way are potentially nested (one might be an ancestor of another), so further downward navigation is not permitted. Expressions that can be statically determined to return a singleton node (for example head(.//title)) generate a result with no such nesting, so they are striding rather than crawling.

  • [Definition: Striding: indicates that the result of a construct contains a sequence of streamed nodes, in document order, that are peers in the sense that none of them is an ancestor or descendant of any other.] This is typically achieved by using one or more steps involving the child or attribute axes only. Use of the outermost function can also result in a striding posture, as can functions such as head or zero-or-one that ensure the result will be a singleton node.

  • [Definition: Roaming: indicates that the nodes returned by an expression could be anywhere in the tree, which inevitably means that the construct cannot be evaluated using streaming.] For example, the posture of an axis step using the following or preceding axis will typically be roaming, which leads the analysis to conclude that the construct is not streamable.

Note:

One way to think about the posture values is as labels for states in a finite state automaton, where the alphabet of symbols accepted by the automaton is the set of 13 XPath axes, and the sentence being parsed is a path expression containing a sequence of axis steps. For example, use of the descendant axis when the current state is striding moves the new state to crawling, and use of the parent axis then takes it to climbing.

The posture of a construct is determined in one of several ways:

  • For axis steps, the posture of the expression is determined by the context posture and the choice of axis. For example, an axis step using the ancestor axis always has a posture of climbing, while an axis step using the child axis, if the context posture is striding, will itself have a posture of striding. The rules for the posture transitions produced by axis steps are given in 19.8.8.9 Streamability of Axis Steps.

  • For many other constructs, the posture is determined by the general streamability rules. These determine the result posture in terms of the operands of the construct and the way in which each operand is used. For example, a construct that accepts a streamed node as the value of an operand, and atomizes that node, will generally have a posture of grounded.

  • Other constructs have their own special rules, which are all listed in this chapter. For example, a call on the root function behaves analogously to an axis step, and is described in 19.8.9.2119.8.9.20 Streamability of the root Function. Special rules are needed for:

    • Constructs that evaluate an operand more than once, such as an XPath for expression;

    • Constructs that have alternatives among their operands, such as an XPath if expression;

    • Constructs that navigate relative to the context item, such as axis steps;

    • Constructs with implicit inputs, such as the context item expression . (dot);

    • Constructs that change the focus, such as a filter expression;

    • Constructs that invoke functions or templates.

The characterization of an expression as striding, crawling, climbing, or roaming applies only to the streamed nodes in the result of the expression. The result of the expression may also contain non-streamed (grounded) nodes or atomic items. 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.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.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 usageabsorption, while I or I indicates that for an or expression, both operands have operand usageinspection. For expressions where further explanation is needed, the table contains a link to the relevant section.

Operand Roles for XPath Expressions
ConstructProforma or Reference to Detailed RulesFurther Information
ExprT, T
ForExprSee 19.8.8.1 Streamability of for Expressions
LetExprlet $var := N return TBinding of variables to streamed nodes is not allowed.
QuantifiedExprSee 19.8.8.2 Streamability of Quantified Expressions
IfExprif (I) then T else TThe then-clause and else-clause form a choice operand group with usage transmission
OrExprI or I
AndExprI and I
StringConcatExprA || A
RangeExprA to A
AdditiveExprA + A, A - A
MultiplicativeExprA * A, A div A, etc.
UnionExprSee 19.8.8.4 Streamability of union, intersect, and except Expressions
IntersectExceptExprSee 19.8.8.4 Streamability of union, intersect, and except Expressions
InstanceOfExprSee 19.8.8.5 Streamability of instance of Expressions
TreatExprSee 19.8.8.6 Streamability of treat as Expressions
CastableExprA castable as TYPE
CastExprA cast as TYPE
UnaryExpr+A, -A
GeneralCompA = A, A < A, A != A, etc.
ValueCompA eq A, A lt A, A ne A, etc.
NodeCompI is I, I << I, I >> ISee Note 1 below
SimpleMapExprSee 19.8.8.7 Streamability of Simple Mapping Expressions
PathExprSee 19.8.8.8 Streamability of Path Expressions
RelativePathExprSee 19.8.8.8 Streamability of Path Expressions
AxisStepSee 19.8.8.9 Streamability of Axis Steps
ForwardStep, ReverseStepSee 19.8.8.9 Streamability of Axis Steps
PostfixExpr: Filter ExpressionSee 19.8.8.10 Streamability of Filter Expressions
PostfixExpr: Dynamic Function CallSee 19.8.8.11 Streamability of Dynamic Function Calls
LiteralThere are no operands, so the construct is grounded and motionless
VarRefSee 19.8.8.12 Streamability of Variable References
ParenthesizedExpr(T)
()There are no operands, so the construct is grounded and motionless
ContextItemExprSee 19.8.8.13 Streamability of the Context Item Expression
FunctionCallSee 19.8.8.14 Streamability of Static Function Calls
NamedFunctionRefSee 19.8.8.15 Streamability of Named Function References
InlineFunctionExprSee 19.8.8.16 Streamability of Inline Function Declarations
MapConstructorSee 19.8.8.17 Streamability of Map Constructors
Lookup (Postfix and Unary)See 19.8.8.18 Streamability of Lookup Expressions
ArrowExprSee 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[ N, N, ... ]
CurlyArrayConstructorarray { 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-id function: let $x := generate-id(.) return descendant::x[generate-id(ancestor::y[1]) = $x]

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 root, as described in 19.8.9.2119.8.9.20 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 motionlesspattern.]

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

19.8.9.11 Streamability of the fold-right Function

The function follows the general streamability rules, with the first argument having operand usagenavigation to reflect the fact that the supplied sequence is processed in reverse order.

19.8.9.12 Streamability of the foot Function

The posture and sweep of the expression foot($x) are defined to be the same as the posture and sweep of the equivalent expression $x[position()=last()]. See 19.8.9.17 Streamability of the last Function.

19.8.9.1319.8.9.12 Streamability of the for-each 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, fn($x as xs:decimal) as xs:decimal {abs($x)}), the operand usage of the argument /*/transaction is determined by the declared type of $x, namely xs:decimal. Since this is an atomic type, the type-determined usage is absorption. Applying this to the general streamability rules, the function call is grounded and consuming.

Note:

In practice, the filter 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.1419.8.9.13 Streamability of the for-each-pair 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-pair 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.1519.8.9.14 Streamability of the function-lookup Function

See 10.3.6 Dynamic Access to Functions for special rules that relate to streamability of calls to the function-lookup function.

With the caveats given there, the function follows the general streamability rules, for a function with two arguments that both have operand usageabsorption.

19.8.9.1619.8.9.15 Streamability of the innermost Function

The function follows the general streamability rules, with the first argument having operand usagenavigation. This is to reflect the fact that the processing is not strictly sequential: it cannot be determined that a node is part of the result sequence of innermost until all its descendants have been read.

19.8.9.1719.8.9.16 Streamability of the last Function

If the context posture for a call on the last function is striding, crawling, or roaming, then the posture of the function is roaming, and the sweep is free-ranging.

In all other cases the function is grounded and motionless.

Note:

The cases where last can be used without affecting streamability are where the context item is either grounded or climbing. The latter condition makes expressions like ancestor::*[@xml:space][last()] streamable.

There are special rules restricting the use of last 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.1819.8.9.17 Streamability of the outermost Function

The single argument to this function has operand usagetransmission.

The streamability of the function call follows the general streamability rules with one exception: if the posture of the argument is crawling, then the posture of the result is striding.

Note:

There are cases where the streaming rules allow the construct outermost(//para) but do not allow //para; the function can therefore be useful in cases where it is known that para elements will not be nested, as well as cases where the application actually wishes to process all para elements except those that are nested within another.

By contrast, the innermost 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.1919.8.9.18 Streamability of the position Function

The position function follows the general streamability rules. Since it has no operands, this means it is grounded and motionless.

Note:

Within an expression, there are no special difficulties in evaluating the position function.

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

19.8.9.2019.8.9.19 Streamability of the reverse Function

The reverse function follows the general streamability rules, with its operand classified as having operand usagenavigation.

Note:

This means in effect that a call on reverse 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.2119.8.9.20 Streamability of the root 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 root 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.9.22 Streamability of the trunk Function

The posture and sweep of the expression trunk($x) are defined to be the same as the posture and sweep of the equivalent expression $x[position()!=last()]. See 19.8.9.17 Streamability of the last Function.

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.7.7 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 usageU = 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 postureP and sweepS 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 usageU = absorption.

    2. The general streamability rules again apply. Again the static typeT of the operand is U{*}, and we need to determine the postureP and sweepS.

    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 postureP and sweepS 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 postureP and sweepS 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 sweepS = 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.7.7 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 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 the expression @currency='USD' is non-positional, as follows:

    1. Rule 1 is satisfied: the predicate does not call position, last, or function-lookup.

    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 usageU = 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.42 Streamability of xsl:value-of.

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

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

    4. The postureP and sweepS are established as follows:

      1. The rules that apply to the call on sum 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 postureP and sweepS 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 usageU′ 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.2119.8.9.20 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 usageU′ 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 totalliteral 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.