Please check the errata for any errors or issues reported since publication.
See also translations.
This document is also available in these non-normative formats: Specification in XML format.
Copyright © 2025 W3C® (MIT, ERCIM, Keio, Beihang). W3C liability, trademark and document use rules apply.
This document defines the streaming feature of XSLT 4.0.
The earlier XSLT 3.0 specification integrated the definition of streaming into the main language specification, although streaming was always an optional feature. In this version, the specification has been modularised so that streaming features are described separately. This has been done in order to make the set of specification documents more manageable both for editors and for readers.
This section describes the status of this document at the time of its publication. Other documents may supersede this document.
This document is a working draft developed and maintained by a W3C Community Group, the XQuery and XSLT Extensions Community Group unofficially known as QT4CG (where "QT" denotes Query and Transformation). This draft is work in progress and should not be considered either stable or complete. Standard W3C copyright and patent conditions apply.
The community group welcomes comments on the specification. Comments are best submitted as issues on the group's GitHub repository.
The community group maintains two extensive test suites, one oriented to XQuery and XPath, the other to XSLT. These can be found at qt4tests and xslt40-test respectively. New tests, or suggestions for correcting existing tests, are welcome. The test suites include extensive metadata describing the conditions for applicability of each test case as well as the expected results. They do not include any test drivers for executing the tests: each implementation is expected to provide its own test driver.
At the time of writing this specification does not fully describe the streamability of all new constructs introduced in XSLT 4.0 and XPath 4.0. This remains a work in progress.
The publications of this community group are dedicated to our co-chair, Michael Sperberg-McQueen (1954–2024).
Changes in 4.0 (next)
Use the arrows to browse significant changes since the 3.1 version of this specification.
Sections with significant changes are marked Δ in the table of contents.
This document defines the streaming feature of the XSLT 4.0 language: see [XSLT 4.0].
Streaming is an optional feature of the XSLT language that enables documents to be transformed that are too large to be held in memory. Stylesheets that aim to achieve streamed processing must adhere to contraints (called streamability rules) that are defined in this specification.
In this specification the phrases must, must not, should, should not, may, required, and recommended, when used in normative text and rendered in small capitals, are to be interpreted as described in [RFC2119].
Where the phrase must, must not, or required relates to the behavior of the XSLT processor, then an implementation is not conformant unless it behaves as specified, subject to the more detailed rules in 13 Conformance.
Where the phrase must, must not, or required relates to a stylesheet then the processor must enforce this constraint on stylesheets by raising an error if the constraint is not satisfied.
Where the phrase should, should not, or recommended relates to a stylesheet then a processor may produce warning messages if the constraint is not satisfied, but must not treat this as an error.
[[Definition: : In this specification, the term implementation-defined refers to a feature where the implementation is allowed some flexibility, and where the choices made by the implementation must be described in documentation that accompanies any conformance claim.]
[[Definition: : The term implementation-dependent refers to a feature where the behavior may vary from one implementation to another, and where the vendor is not expected to provide a full specification of the behavior.] (This might apply, for example, to limits on the size of source documents that can be transformed.)
In all cases where this specification leaves the behavior implementation-defined or implementation-dependent, the implementation has the option of providing mechanisms that allow the user to influence the behavior.
A paragraph labeled as a Note or described as an example is non-normative.
[[Definition: : The term streaming refers to a manner of processing in which XML documents (such as source and result documents) are not represented by a complete tree of nodes occupying memory proportional to document size, but instead are processed “on the fly” as a sequence of events, similar in concept to the stream of events notified by an XML parser to represent markup in lexical XML.]
[[Definition: : A streamed document is a source treeXT that is processed using streaming, that is, without constructing a complete tree of nodes in memory.]
[[Definition: : A streamed node is a node in a streamed document.]
Many processors implementing earlier versions of this specification adopted an architecture that allowed streaming of the result treeXT directly to a serializer, without first materializing the complete result tree in memory. Streaming of the source treeXT, however, has proved to be more difficult without subsetting the language. This has created a situation where documents exceeding the capacity of virtual memory could not be transformed. XSLT 3.0 therefore introduced facilities allowing stylesheets to be written in a way that makes streaming of source documents possible, without excessive reliance on processor-specific optimization techniques.
Streaming achieves two important objectives: it allows large documents to be transformed without requiring correspondingly large amounts of memory; and it allows the processor to start producing output before it has finished receiving its input, thus reducing latency.
This specification does not attempt to legislate precisely which implementation techniques fall under the definition of streaming, and which do not. A number of techniques are available that reduce memory requirements, while still requiring a degree of buffering, or allocation of memory to partial results. A stylesheet that requests streaming of a source document is indicating that the processor should avoid assuming that the entire source document will fit in memory; in return, the stylesheet must be written in a way that makes streaming possible. This specification does not attempt to describe the algorithms that the processor should actually use, or to impose quantitative constraints on the resources that these algorithms should consume.
Nothing in the XSLT specification prevents a processor using streaming whenever it sees an opportunity to do so. However, experience has shown that in order to achieve streaming, it is often necessary to write stylesheet code in such a way as to make this possible. Therefore, XSLT provides explicit constructs allowing the stylesheet author to request streaming, and defines explicit static constraints on the structure of the code which are designed to make streaming possible.
A processor that claims conformance with the streaming option offers a guarantee that when streaming is requested for a source document, and when the stylesheet conforms to the rules that make the processing guaranteed-streamable, then an algorithm will be adopted in which memory consumption is either completely independent of document size, or increases only very slowly as document size increases, allowing documents to be processed that are orders-of-magnitude larger than the physical memory available. A processor that does not claim conformance with the streaming option must still process a stylesheet and deliver the correct results, but is not required to use streaming algorithms, and may therefore fail with out-of-memory errors when presented with large source documents.
Apart from the fact that there are constructs to request streaming, and rules that must be followed to guarantee that streaming is possible, the language has been designed so there are as few differences as possible between streaming and non-streaming evaluation. The semantics of the language continue to be expressed in terms of the XDM data model, which is substantively unchanged; but readers must take care to observe that when terms like “node” and “axis” are used, the concepts are completely abstract and may have no direct representation in the run-time execution environment.
Streamed processing of a document can be initiated in one of three ways:
The initial modeXT can be declared as a streamable modeXT. In this case the initial match selectionXT will generally be a document node (or sequence of document nodes), supplied by the calling application in a form that allows streaming (that is, in some form other than a tree in memory; for example, as a reference to a push or pull XML parser primed to deliver a stream of events). The type of these nodes can be constrained by using the attribute on-no-match="fail" on the initial modeXT, and using this mode only for processing the top-level nodes.
Streamed processing of any document can be initiated using the xsl:source-document instruction. This has an attribute href whose value is the URI of a document to be processed, and an attribute streamable that indicates whether it is to be processed using streaming; the actual processing to be applied is defined by the instructions written as children of the xsl:source-document instruction.
Streamed merging of a set of input documents can be initiated using the xsl:merge instruction.
The rules for streamability, which are defined in detail in 3 Streamability Analysis Principles, impose two main constraints:
The only nodes reachable from the node that is currently being processed are its attributes and namespaces, its ancestors and their attributes and namespaces, and its descendants and their attributes and namespaces. The siblings of the node, and the siblings of its ancestors, are not reachable in the tree, and any attempt to use their values is a static errorXT.
When processing a given node in the tree, each descendant node can only be visited once. Essentially this allows two styles of processing: either visit each of the children once, and then process that child with the same restrictions applied; or process all the descendants in a single pass, in which case it is not possible while processing a descendant to make any further downward selection.
The second restriction, that only one visit to the children is allowed, means that XSLT code that was not designed with streaming in mind will often need to be rewritten to make it streamable. In many cases it is possible to do this using a technique sometimes called windowing or burst-mode streaming (note this is not quite the same meaning as windowing in XQuery 3.0). Many XML documents consist of a large number of elements, each of manageable size, representing transactions or business objects where each such element can be processed independently: in such cases, an effective design pattern is to write a streaming transformation that takes a snapshot of each element in turn, processing the snapshot using the full power of the XSLT language. Each snapshot is a tree built in memory and is therefore fully navigable. For details see the snapshot and copy-of functions.
The new facility of accumulators allows applications complete control over how much information is retained (and by implication, how much memory is required) in the course of a pass over a streamed document. An accumulator computes a value for every node in a streamed document: or more accurately, two values, one for the first visit to a node (before visiting its descendants), and a second value for the second visit to the node (after visiting the descendants). The computation is structured in such a way that the value for a given node can depend only on the value for the previous node in document order together with the data available when positioned at the current node (for example, the attribute values). Based on the well-established fold operation of functional programming languages, accumulators provide the convenience and economy of mutable variables while remaining within the constraints of a purely declarative processing model.
When streaming is initiated, for example using the xsl:source-document instruction, it is necessary to declare which accumulators are applicable to the streamed document.
Streaming applications often fall into one of the following categories:
Aggregation applications, where a single aggregation operation (perhaps count, sum, exists, or distinct-values) is applied to a set of elements selected from the streamed source document by means of a path expression.
Record-at-a-time applications, where the source document consists of a long sequence of elements with similar structure (“records”), and each “record” is processed using the same logic, independently of any other “records”. This kind of processing is facilitated using the snapshot and copy-of function mentioned earlier.
Grouping applications, where the output follows the structure of the input, except that an extra layer of hierarchy is added. For example, the input might be a flat series of banking transactions in date/time order, and the output might contain the same transactions grouped by date.
Accumulator applications, which are the same as record-at-a-time applications, except that the processing of one “record” might depend on data encountered earlier in the document. A classic example is processing a sequence of banking transactions in which the input transaction contains a debit or credit amount, and the output adds a running total (the account balance). The xsl:iterate instruction has been introduced to facilitate this style of processing.
Isomorphic transformations, in which there is an ordered (often largely one-to-one) relationship between the nodes of the source tree and the nodes of the result tree: for example, transformations that involve only the renaming or selective deletion of nodes, or scalar manipulations of the values held in the leaf nodes. Such transformations are most conveniently expressed using recursive application of template rules. This is possible with a streamed input document only if all the template rules adhere to the constraints required for streamability. To enforce these rules, while still allowing unrestricted processing of other documents within the same transformation, all streaming evaluation must be carried out using a specific modeXT, which is declared to be a streaming mode by means of an xsl:mode declaration in the stylesheet.
There are important classes of application in which streaming is possible only if multiple streams can be processed in parallel. This specification therefore provides facilities:
allowing multiple sorted input sequences to be merged into one sorted output sequence (the xsl:merge instruction)
allowing multiple output sequences to be generated during a single pass of an input sequence (the xsl:fork instruction).
These facilities have been designed in such a way that they can readily be implemented using streaming, that is, without materializing the input or output sequences in memory.
This section describes the principles used to determine properties of constructs in the stylesheetXT that are used in the analysis of streamability. Specifically, it introduces the concepts of the posture and sweep of a construct, which enable the streamability of the stylesheet to be assessed.
These properties are used, for example, to determine the streamability of:
The xsl:source-document instruction: see 4 Streaming Source Documents
Stylesheet functionsXT: see 8.1 Classifying Stylesheet Functions
The xsl:merge instruction: see 10 Streamable Merging
In each case, the conditions for constructs to be guaranteed-streamable are defined in terms of these properties. The result of this analysis in turn (see 3.1 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 componentXT in the stylesheet (and in the case of template rulesXT, 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 packageXT. 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 constructorXT, an instructionXT, an attribute setXT, a value templateXT, an expressionXT, or a patternXT.]
These constructs are classified into construct kinds: in particular, instructionsXT are classified according to the name of the XSLT instruction, and expressionsXT 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.)
Certain constructs allow a stylesheet author to declare that a construct is streamable. Specifically:
Specifying streamable="yes" on xsl:mode declares that all template rules in that mode (and all template rules that specify mode="#all") are streamable;
Specifying streamable="yes" on xsl:source-document declares that its contained sequence constructor is streamable;
Specifying streamable="yes" on xsl:function declares that the stylesheet functionXT in question is streamable;
Specifying streamable="yes" on xsl:attribute-set declares that the attribute set in question is streamable;
Specifying streamable="yes" (explicitly or implicitly) on xsl:merge-source declares that the merging process is streamable with respect to that particular input.
Specifying streamable="yes" on xsl:accumulator declares that the accumulator can be evaluated on a streamed document.
[[Definition: : The above constructs (template rules belonging to a mode declared with streamable="yes"; and xsl:source-document, xsl:attribute-set, xsl:function, xsl:merge-source, and xsl:accumulator elements specifying streamable="yes") are said to be declared-streamable.]
In each case the construct in question is said to be guaranteed-streamable if it satisfies two conditions:
The construct is declared-streamable.
Streamability analysis following the rules defined in this specification determines that streamed processing is possible (the detailed conditions vary from one construct to another).
[[Definition: : A guaranteed-streamable construct is a construct that is declared to be streamable and that follows the particular rules for that construct to make streaming possible, as defined by the analysis in this specification.]
For a streaming processor, that is, a processor that claims conformance with the streaming feature:
If a construct is guaranteed-streamable and the input is provided in streamable form, then the input must be processed using streaming.
Note:
The requirement to process the input using streaming does not apply if the processor is able to determine that this would convey no benefit: for example, if the input is supplied as a tree in memory. However, this does not remove the requirement to verify that the relevant stylesheet constructs are guaranteed-streamable.
If a construct is declared as streamable but is not guaranteed-streamable (that is, if it fails to satisfy the conditions for streamability defined in this specification), then the processor must be prepared to do any one of the following at user option:
Raise a static error [see ERR XTSE3430]
Process the stylesheet as if it were a non-streaming processor (see below)
Process the stylesheet with streaming if it is able to do so, or raise a static error [see ERR XTSE3430] if it is not able to do so.
[ERR XTSE3430] It is a static errorXT if a packageXT 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.
[[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:
The required typeXT of the operand. This is explicit in the case of function calls (the required type is defined in the function signature of the corresponding function). In other cases it is implicit in the detailed rules for the construct in question. In practice streamability analysis makes only modest use of the required type; the main case where it is relevant is for a function or template call, where knowing that the required type is atomic enables the inference that the operand usage for a supplied node is absorption.
[[Definition: : The operand usage. This gives information, in the case where the operand value contains nodes, about how those nodes are used. The operand usage takes one of the values absorption, inspection, transmission, or navigation.] The meanings of these terms are explained in 3.2 Operand Roles. If the required type of the operand does not permit nodes to be supplied (for example because the required type is a function item or a map), then the operand usage is inspection, because the only run-time operation on a supplied node will be to inspect it, discover it is a node, and raise a type error.
In the particular case where the required type is atomic, and any supplied nodes are atomized, the operand usage will be absorption, because atomizeXT is a special case of absorption.
[[Definition: : Whether or not the operand is higher-order. For this purpose an operand O of a construct C is higher-order if the semantics of C potentially require O to be evaluated more than once during a single evaluation of C.] More specifically, O is a higher-order operand of C if any of the following conditions is true:
The context itemXT for evaluation of O is different from the context item for evaluation of C.
C is an instructionXT and O is a patternXT (as with the from and count attributes of xsl:number, and the group-starting-with and group-ending-with attributes of xsl:for-each-group).
C is an XPath for, some, or every expression and O is the expression in its return or satisfies clause.
C is an inline function declaration and O is the expression in its body.
Note:
There is one known case where this definition makes an operand higher-order even though it is only evaluated once: specifically, the sequence constructor contained in the body of an xsl:copy instruction that has a select attribute. See 12.5.12 Streamability of xsl:copy for further details.
An operand role gives information about the operands of a particular kind of construct. The two important properties of an operand role are the required type and the operand usage.
The usage of an operand role is relevant only when the value of an operand supplied in that role is a node, or a sequence that contains nodes. It is one of the following:
[[Definition: : An operand usage of absorption indicates that the construct reads the subtree(s) rooted at a supplied node(s).] Examples are constructs that atomize their operands, or that obtain the string value of a supplied node, or that copy the supplied node to a new tree. Another example is the deep-equal function, which compares the subtrees rooted at the nodes supplied in its first two arguments.
[[Definition: : An operand usage of inspection indicates that the construct accesses properties of a supplied node that are available without reading its subtree.] Examples are functions such as name and base-uri, and the instance of expression which tests the type of a node (or other item), or functions such as count, exists, and boolean which are only interested in the existence of the node, and not in its properties.
[[Definition: : An operand usage of transmission indicates that the construct will (potentially) return a supplied node as part of its result to the calling construct (that is, to its parent in the construct tree).] It also indicates that document order is preserved: if the input is in document order, then the result must be in document order. An example is a filter expression, where nodes in the base expression (the expression being filtered) will typically appear in the result of the filter expression, in their original order.
[[Definition: : An operand usage of navigation indicates that the construct may navigate freely from the supplied node to other nodes in the same tree, in a way that is not constrained by the streamability rules.] This covers several cases: cases where it is known that the construct performs impermissible navigation (for example, the xsl:number instruction) or reordering (the reverse function), or that require look-ahead (the innermost function) and also cases where the analysis is unable to determine what use is made of the node, for example because it is passed as an argument to a user-defined function, or retained in a variable.
The concept of operand usage is not used for all constructs (for example, it is not used in the analysis of path expressions). Where it is used, the assignment of operand usages to each operand role of a construct is defined in the relevant subsection of 12 Streamability of Specific Constructs.
[[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 rulesXT 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:
The static type of the construct. When the construct is evaluated, its value will always be an instance of this type. The value is a U-type; although type inferencing is capable of determining information about the cardinality as well as the item type, the streamability analysis makes no use of this.
The context item type: that is, the static type of the context itemXT potentially used as input to the construct. When the construct is evaluated, the context item used to evaluate the construct (if it is used at all) will be an instance of this type.
[[Definition: : The posture of the expression. This captures information about the way in which the streamed input document is positioned on return from evaluating the construct. The posture takes one of the values climbing, striding, crawling, roaming, or grounded.] The meanings of these terms are explained in 3.8 Posture.
[[Definition: : The context posture. This captures information about how the context itemXT 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 3.8.2 Determining the Context Posture.
The sweep of the construct. The sweep of a construct gives information about whether and how the evaluation of the construct changes the current position in a streamed input document. The possible values are motionless, consuming, and free-ranging. These terms are explained in 3.9 Sweep.
The values of these properties for a top-level construct such as the body of a template rule determine whether the construct is streamable.
The values of these properties are not independent. For example, if the static type is atomic, then the posture will always be grounded; if the sweep is free-ranging, then the posture will always be roaming.
The posture and sweep of a construct, as defined above, are calculated in relation to a particular streamed input document. If there is more than one streamed input document, then a construct that is motionless with respect to one streamed input might be consuming with respect to another. In practice, though, the streamability analysis is only ever concerned with one particular streamed input at a time; constructs are analyzed in relation to the innermost containing xsl:template, xsl:source-document, xsl:accumulator, or xsl:merge-source element, and this container implicitly defines the streamed input document that is relevant. The streamed input document affecting a construct is always the document that contains the context item for evaluation of that construct.
[[Definition: : The static type of a construct is such that all values produced by evaluating the construct will conform to that type. The static type of a construct comprises a U-type and a cardinality. A cardinality is a range of integers (from min to max).]
[[Definition: : A U-type is a set of fundamental item types.]
[[Definition: : There are 29 fundamental item types: the 7 node kinds defined in [XDM 4.0] (element, attribute, etc.), the 19 primitive atomic types defined in [XML Schema Part 2], plus the types fn(*), xs:untypedAtomic, and JNode. The fundamental item types are disjoint, and every item is an instance of exactly one of them.]
More specifically, the fundamental item types are:
document-node(), element(), attribute(), text(), comment(), processing-instruction(), namespace-node();
xs:boolean, xs:double, xs:decimal, xs:float, xs:string, xs:dateTime, xs:date, xs:time, xs:gYear, xs:gYearMonth, xs:gMonth, xs:gMonthDay, xs:gDay, xs:anyURI, xs:QName, xs:NOTATION, xs:base64Binary, xs:hexBinary, xs:duration
fn(*)
xs:untypedAtomic
JNode
TODO: extend the analysis to include JNodes.
A value V (in general, a sequence) is an instance of a U-typeU 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 ItemTypeXP 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 items (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 SequenceTypeXT syntax, there is therefore a mapping defined from SequenceTypes to U-types. The mapping is as follows:
The SequenceTypeXTempty-sequence() maps to U{}
For every other SequenceTypeXT, the mapping depends only on the item type and ignores the occurrence indicator. The mapping from item types is as follows:
item() maps to U{*}
A choice item type (A | B | C) maps to the union of the U-types corresponding to A, B, and C.
AnyKindTest (node()) maps to U{N}
DocumentTest maps to U{document-node()}
ElementTest and SchemaElementTest map to U{element()}
AttributeTest and SchemaAttributeTest map to U{attribute()}
TextTest maps to U{text()}
CommentTest maps to U{comment()}
PITest maps to U{processing-instruction()}
NamespaceNodeTest maps to U{namespace-node()}
FunctionType, MapType, and ArrayType and RecordType map to U{fn(*)}
The QName xs:error maps to U{}
A QName Q representing an atomic type that is a fundamental item type maps to U{Q}
A QName Q representing an atomic type derived from a fundamental item type F maps to U{F}
A QName Q representing a pure union type maps to a U-type containing the fundamental item types present in the transitive membership of the union, or from which the transitive members of the union are derived.
[[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 focusXT 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, A[B], A?[B], or A -> B the focus for evaluating B is A. More generally:
[[Definition: : A focus-changing construct is a construct that has one or more operands that are evaluated with a different focusXT from the parent construct.]
Note:
Examples of focus-changing constructs include the instructions xsl:for-each, xsl:iterate, and xsl:for-each-group; path expressions, filter expressions, and simple mapping expressions; and all patterns.
[[Definition: : Within a focus-changing construct there is in many cases one operand whose value determines the focusXT for evaluating other operands; this is referred to as the controlling operand.]
Note:
For example, the controlling operand of an xsl:for-each, xsl:iterate, or xsl:for-each-group instruction is the expression in its select attribute; the controlling operand of a filter expression E[P] is E, and the controlling operand of a simple mapping expression A!B is A.
[[Definition: : Within a focus-changing construct there are one or more operands that are evaluated with a focusXT determined by the controlling operand (or in some cases such as xsl:on-completion, with an absentXTfocusXT); these are referred to as controlled operands.]
Note:
For example, the main controlled operand of an xsl:for-each, xsl:iterate, or xsl:for-each-group instruction is the contained sequence constructor; the controlled operand of a filter expression E[P] is P, and the controlled operand of a simple mapping expression A!B is B.
[[Definition: : The focus-setting container of a construct C is the innermost focus-changing constructF (if one exists) such that C is directly or indirectly contained in a controlled operand of F. If there is no such construct F, then the focus-setting container is the containing declarationXT, for example an xsl:function or xsl:template element.]
Note:
For example, if an instruction appears as a child of xsl:for-each, then its focus-setting container is the xsl:for-each instruction; if an expression appears within the predicate of a filter expression, its focus-setting container is the filter expression.
The context item type of a construct C is the first of the following that applies:
If the focus-setting container of C is an xsl:function element, an inline function declaration, or an xsl:on-completion element, then the context item type is U{}.
Note:
This is essentially an error case; expressions that depend on the focus should not normally appear within a construct that sets the focus to absentXT.
If the focus-setting container of C is an xsl:source-document instruction, then the context item type is U{document-node()}.
If the focus-setting container of C is a template ruleXT, then the context item type is the match type of the match pattern of the template rule, defined below.
If the focus-setting container of C is a PredicatePattern, then the context item type is U{*}.
If the focus-setting container is a global variableXT declaration, the context item type is determined by the type attribute of the xsl:global-context-item declaration, defaulting to U{*}, or U{} if the xsl:global-context-item declaration specifies use="absent".
If the focus-setting container is any other declarationXT, for example xsl:key or xsl:accumulator, the context item type is U{*}.
Otherwise, the context item type is the static type (see 3.5 Determining the Static Type of a Construct) of the controlling operand of the focus-setting container of C.
[[Definition: : The match type of a patternXT 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 3.5 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()}
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 12.7.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 listed in 12 Streamability of Specific Constructs. For example, a call on the root function behaves analogously to an axis step, and is described in 12.8.21 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.
[[Definition: : For some construct kinds, one or more operand roles may be defined to form a choice operand group. This concept is used where it is known that operands are mutually exclusive (for example the then and else clauses in a conditional expression).]
[[Definition: : The combined posture of a choice operand group is determined by the postures of the operands in the group (the operand postures), and is the first of the following that applies:
If any of the operand postures is roaming, then the combined posture is roaming.
If all of the operand postures are grounded, then the combined posture is grounded.
If one or more of the operand postures is climbing and the remainder (if any) are grounded, then the combined posture is climbing.
If one or more of the operand postures is striding and the remainder (if any) are grounded, then the combined posture is striding.
If one or more of the operand postures is crawling and each of the remainder (if any) is either striding or grounded, then the combined posture is crawling.
Otherwise (for example, if the group includes both an operand with climbing posture and one with crawling posture), the combined posture is roaming.
]
[[Definition: : 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 motionlessconstruct is any construct deemed motionless by the rules for that construct (typically given in 12 Streamability of Specific Constructs).] 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 for that construct (typically given in 12 Streamability of Specific Constructs).] 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 for that construct (typically given in 12 Streamability of Specific Constructs).] Informally, a free-ranging construct is one whose evaluation may require access to information that is not available from the subtree rooted at the current node, together with information about ancestors of the current node and their attributes.
The table below shows some examples of expressions having different combinations of posture and sweep.
| Motionless | Consuming | Free-Ranging | |
|---|---|---|---|
| Grounded | name() | string(title) | See Note |
| Climbing | parent::* | child::x/ancestor::y | See Note |
| Striding | @status | child::* | See Note |
| Crawling | The subexpression . in //a/. | descendant::* | //x[child::y] |
| Roaming | See Note | See Note | preceding::* |
Note:
In all cases where either the posture is roaming, or the sweep is free-ranging, or both, the effect is to make an expression non-streamable. For convenience, therefore, evaluation of the streamability rules in most cases returns the values roaming and free-ranging only in combination with each other. In cases where the rules return a posture of roaming combined with some other sweep, or a sweep of free-ranging with some other posture, the final result of the analysis is always the same as if the expression were both roaming and free-ranging.
For an example of a case where an expression is roaming but not free-ranging, consider the right-hand operand of the relative path expression (preceding::x/.). The rules for the streamability of a context item expression (see 12.7.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 12.7.8 Streamability of Path Expressions), so the apparent inconsistency is transient.
[[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 templateXT, a sequence constructorXT, the xsl:text and xsl:value-of instructions, and a call to the doc function.
The rules determine both the posture and sweep of a construct. To determine the posture and sweep of a construct C, assuming these general rules are applicable to that kind of construct:
For each operand of C:
Establish:
The static typeT of the operand (see 3.5 Determining the Static Type of a Construct).
Note:
The static type is a U-type. For example, the static type of the expression (@*, *) is U{element(), attribute()}.
The sweepS and postureP of the operand (by applying the rules appropriate to that operand).
The operand usageU corresponding to the role of the operand within C.
Compute the adjusted sweep S′ of the operand by taking the first of the following that applies:
If S is free-ranging or P is roaming, then S′ is free-ranging. (In this case the posture and sweep of C are roaming and free-ranging, regardless of any other operands.)
If P is grounded, then S′ is S.
Otherwise (P is not grounded, which implies that the operand is capable of returning streamed nodes), compute S′ as follows:
Compute the adjusted usage U′ as follows:
If U is absorption and the intersection of T with U{element(), document-node()} is U{} (that is, if T is a type that does not allow nodes with children), then U′ is inspection.
Note:
This is because the entire subtree of nodes such as text nodes is available without reading further data from the input stream.
Otherwise, U′ is U.
Compute the adjusted sweepS′ from the table below:
| Posture (P) | Adjusted Usage (U') | |||
|---|---|---|---|---|
| Absorption | Inspection | Transmission | Navigation | |
| Climbing | Free-ranging | S | S | Free-ranging |
| Striding | Consuming | S | S | Free-ranging |
| Crawling | Consuming | S | S | Free-ranging |
[[Definition: : An operand is potentially consuming if at least one of the following conditions applies:
The operand usage is transmission and the operand is not grounded.
]
Having computed the adjusted sweep S′(o) of each operando, the posture and sweep of C are the first of the following that applies:
If C has no operands, then grounded and motionless.
If any operand o has an adjusted sweep S′(o) of free-ranging, then roaming and free-ranging.
If more than one operand is potentially consuming, then:
If all these operands form part of a choice operand group, then the posture of C is the combined posture of the operands in this group, and the sweep of C is the widest sweep of the operands in this group
If all these operands have S′ = motionless, (which necessarily means they have U′ = U = transmission) and if they all have the same postureP0, then motionless with postureP0.
Note:
For example, the expression (@a, @b) is motionless and striding.
Otherwise, roaming and free-ranging.
If exactly one operand o is potentially consuming, then:
If o is a higher-order operand of C, then roaming and free-ranging.
If the operand usage of o is absorption or inspection, then grounded and consuming.
If the posture of o is crawling and C is a function call of a built-in function whose signature indicates a return type with a maximum cardinality of one then striding and the adjusted sweep of o.
Note:
Although this rule is written in general terms, the only functions that it applies to (at the time of publication) are head, exactly-one, and zero-or-one. This rule only applies if the argument usage is transmission (other cases having been handled by earlier rules); of the built-in functions, the three functions listed are the only ones having an argument with usage transmission and a return type with maximum cardinality one.
Otherwise (the operand usage of o is transmission), the posture and adjusted sweep of o.
Otherwise (all operands are motionless) grounded and motionless.
Note:
The rules ensure that if more than one operand is consuming, that is, if more than one operand reads the subtree of the context node in a way that would cause the current position of the input stream to change, then the construct is not streamable.
The rules also prevent multiple streamed nodes being returned in the result of an expression if they are delivered by different operands. For example, the expression count((.., *)) is not guaranteed streamable. This is to make static analysis possible: the posture needs to be statically determined to ensure that streaming does not fail at execution time. It is permitted, however, for streamed nodes to be mixed in a sequence with non-streamed nodes or with atomic items; 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.
The streamability attribute of xsl:function is used to assign the function to one of a number of streamability categories. The various categories, and their effect on the streamability of function calls, are described in 8.1 Classifying Stylesheet Functions.
The streamability category of a function characterizes the way in which the function processes any streamed nodes supplied in the first argument to the function. (In general, streamed nodes cannot be supplied in other arguments, unless they are atomized by the coercion rulesXT.) The streamability attribute is therefore not applicable unless the function takes at least one argument.
[ERR XTSE3155] It is a static error if an xsl:function element with no xsl:param children has a streamability attribute with any value other than unclassified.
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 functionXT only if one of the following conditions is true:
The stylesheet function is declared-streamable, and the argument in question is the first argument of the function call.
The corresponding function parameterXT is declared with a required typeXT that triggers atomizationXT of any supplied node.
[[Definition: : The first parameterXT of a declared-streamablestylesheet functionXT 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 12.7.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 constructorXT 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 constructorXT, which is done according to the rules in 12.4 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 12.7.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 3.1 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.
XPath expressions are classified using the rules in this section.
In the analysis that follows, expressionsXT are classified according to the most specific production rule that they match for which there is an entry in this section. A production P is considered more specific than a production Q (Q ≠ P) if every expression that matches P also matches Q. For example:
The expression 3 satisfies the productions NumericLiteral, Literal, and ArithmeticExpression; the most specific of these for which there is an entry in this section is Literal.
The expression text() (appearing as an expression) is a TextTest, and therefore a KindTest, which is itself a NodeTest, and therefore an AxisStep with a defaulted ForwardAxis. The most specific of these for which there is an entry in this section is AxisStep. Although the expression is also a RelativePathExpr, that production is less specific than AxisStep so its rules do not apply.
The expression section/title is a RelativePathExpr, for which there is an entry in this section. Although the expression is also a PathExpr, that production is less specific than RelativePathExpr so its rules do not apply.
The production rules for different kinds of expression are listed (with their names and numbers) in the order in which they appear in Appendix A.1 of the XPath 3.0 specification; rules are also given for new constructs introduced by XPath 3.1. Where two numbers are given, they are the production rule numbers in XPath 3.0 and XPath 3.1 respectively; where there is a single number, it is the production rule number in XPath 3.1.
Many expressions can be analyzed using the general streamability rules. These are indicated in the table below by means of a simple proforma in which the operand roles are represented by a short code (A = absorption, I = inspection, T = transmission, N = navigation). For example the proforma A + A indicates that for an arithmetic expression, both operands have operand 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.
| Construct | Proforma or Reference to Detailed Rules | Further Information |
|---|---|---|
| Expr | T, T | |
| ForExpr | See 12.7.1 Streamability of for Expressions | |
| LetExpr | let $var := N return T | Binding of variables to streamed nodes is not allowed. |
| QuantifiedExpr | See 12.7.2 Streamability of Quantified Expressions | |
| IfExpr | if (I) then T else T | The then-clause and else-clause form a choice operand group with usage transmission |
| OrExpr | I or I | |
| AndExpr | I and I | |
| StringConcatExpr | A || A | |
| RangeExpr | A to A | |
| AdditiveExpr | A + A, A - A | |
| MultiplicativeExpr | A * A, A div A, etc. | |
| UnionExpr | See 12.7.4 Streamability of union, intersect, and except Expressions | |
| IntersectExceptExpr | See 12.7.4 Streamability of union, intersect, and except Expressions | |
| InstanceOfExpr | See 12.7.5 Streamability of instance of Expressions | |
| TreatExpr | See 12.7.6 Streamability of treat as Expressions | |
| CastableExpr | A castable as TYPE | |
| CastExpr | A cast as TYPE | |
| UnaryExpr | +A, -A | |
| GeneralComp | A = A, A < A, A != A, etc. | |
| ValueComp | A eq A, A lt A, A ne A, etc. | |
| NodeComp | I is I, I << I, I >> I | See Note 1 below |
| SimpleMapExpr | See 12.7.7 Streamability of Simple Mapping Expressions | |
| PathExpr | See 12.7.8 Streamability of Path Expressions | |
| RelativePathExpr | See 12.7.8 Streamability of Path Expressions | |
| AxisStep | See 12.7.9 Streamability of Axis Steps | |
| ForwardStep, ReverseStep | See 12.7.9 Streamability of Axis Steps | |
| PostfixExpr: Filter Expression | See 12.7.10 Streamability of Filter Expressions | |
| PostfixExpr: Dynamic Function Call | See 12.7.11 Streamability of Dynamic Function Calls | |
| Literal | There are no operands, so the construct is grounded and motionless | |
| VarRef | See 12.7.12 Streamability of Variable References | |
| ParenthesizedExpr | (T) | |
() | There are no operands, so the construct is grounded and motionless | |
| ContextItemExpr | See 12.7.13 Streamability of the Context Item Expression | |
| FunctionCall | See 12.7.14 Streamability of Static Function Calls | |
| NamedFunctionRef | See 12.7.15 Streamability of Named Function References | |
| InlineFunctionExpr | See 12.7.16 Streamability of Inline Function Declarations | |
| MapConstructor | See 12.7.17 Streamability of Map Constructors | |
| Lookup (Postfix and Unary) | See 12.7.18 Streamability of Lookup Expressions | |
| ArrowExpr | See 12.7.14 Streamability of Static Function Calls and 12.7.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, ... ] | |
| CurlyArrayConstructor | array { N, N, ... } |
Note:
The operators is, <<, and >> apply to streamed nodes just as to any other nodes, though there are few practical situations where they will be useful. A streamed document conforms to the rules of the XDM data model, and its nodes are therefore distinct and ordered. They follow the usual rules, for example that a parent node precedes its children in document order. Expressions such as .. is parent::X or ancestor::x[1] << ancestor::y[1] are therefore perfectly meaningful. The usefulness of the operators is limited by the fact that variables cannot be bound to nodes in a streamed document. It is permitted, though perhaps not useful, for one of the operands to be consuming: one can write . << child::x, and the resulting expression is (by applying the general rules) consuming and grounded.
The restriction that variables cannot be bound to streamed nodes prevents writing of expressions such as let $x := . return descendant::x[ancestor::y[1] is $x]. As a workaround, the intended effect can be achieved by comparing node identity using the generate-id function: let $x := generate-id(.) return descendant::x[generate-id(ancestor::y[1]) = $x]
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 12.8.21 Streamability of the root Function.
Note:
Taken together, these rewrites have the effect that a path expression such as //a is streamable only if the statically determined context item type is document-node(), which will be the case for example immediately within xsl:source-document, or in a template rule with match="/".
A RelativePathExpr with more than two operands (such as a/b/c) is taken as a tree of binary expressions (that is, (a/b)/c).
The sweep of a relative path expression is the wider sweep of the two operands, where the ordering of increasing width is motionless, consuming, free-ranging.
Note:
Examples:
The sweep of a/@code is consuming (the wider of consuming and motionless).
The sweep of a/descendant::b is consuming (the wider of consuming and consuming).
The sweep of ./@code is motionless (the wider of motionless and motionless).
The sweep of ./a is consuming (the wider of motionless and consuming).
The sweep of a/following::b is free-ranging (the wider of consuming and free-ranging).
The sweep of ./. is motionless (the wider of motionless and motionless).
The posture of a relative path expression is assessed in two phases, as follows:
First, the provisional posture is determined as follows: The provisional posture of the expression is the posture of the right-hand operand, assessed with a context posture and type set to the posture and type of the left-hand operand; and the provisional sweep is the wider of the sweeps of the two operands.
If the provisional posture is roaming, then it is reassessed as follows:
[[Definition: : A RelativePathExpr is a scanning expression if and only if it is syntactically equivalent to some motionlesspatternXT.]
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 [XSLT 4.0] section 6.3.2 Syntax of Patterns), and if, when considered as a pattern, the pattern is motionless according to the rules in 12.9 Classifying Patterns.
In practice, the test as to whether the construct is equivalent to a pattern is likely to be made by examining the structure of the expression tree, rather than by re-parsing the lexical form of the expression against the grammar for patterns; but the outcome is the same.
If the expression is a scanning expression then:
Otherwise (if the provisional posture is not roaming, or the expression is not a scanning expression), the posture of the expression is the provisional posture.
Note:
The special rules for scanning expressions are designed to ensure that expressions such as //section/head are streamable. The problem with such an expression is that it is possible to have two nested sections A and B, where A is the parent of B and thus precedes B in document order, but where there are children of A that come after children of B in document order. This means that a nested-loop strategy for the evaluation of /descendant::section/child::head is not guaranteed to deliver nodes in document order without a sort, and is therefore not a viable strategy for streaming.
However, there is a different strategy for evaluating such an expression, which is in effect to rewrite the expression as /descendant::head[parent::section]; specifically, it is possible to scan all descendants in document order, looking for a head element that has a section parent. Hence the term scanning expressions.
The expressions that qualify as scanning expressions are paths that can be evaluated by scanning all descendants and testing each one (independently) to see whether the elements on its ancestor axis match the specified path. The subset of expressions that qualify as scanning expressions is therefore the same as the subset that qualify as motionless patterns.
Scanning expressions cannot use positional predicates: for example //section/head[1] is not recognized as a scanning expression because this would require information about a streamed node (specifically, about its preceding siblings) that is not retained during streaming.
Note:
Perhaps surprisingly, the expression .//section/head is not a scanning expression and is therefore not guaranteed streamable. This is because it does not take the syntactic form of a patternXT. 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 12.9 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 3.1 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.
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 3.10 General Streamability Rules, 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:build(N, I)
array:empty(I)
array:filter(I, I)
array:flatten(T)
array:fold-left(I, N, I)
array:fold-right(I, N, I)
array:foot – See
array:for-each(I, I)
array:for-each-pair(I, I, I)
array:get(I, A)
array:get(I, A, A)
array:head(I)
array:index-of(A, A, A)
array:index-where(I, I)
array:insert-before(I, A, N)
array:items(I)
array:join(I)
array:members(I)
array:of-members(I)
array:put(I, I, N)
array:remove(I, A)
array:reverse(I)
array:size(I)
array:slice(I, A, A, A)
array:sort(N, A, I)
array:sort-by(N, A)
array:sort-with(A, A)
array:split(I)
array:subarray(I, A, A)
array:tail(I)
array:trunk – See
fn:abs(A)
fn:accumulator-after – See 12.8.1 Streamability of the accumulator-after Function
fn:accumulator-before – See 12.8.2 Streamability of the accumulator-before Function
fn:adjust-date-to-timezone(A, A)
fn:adjust-dateTime-to-timezone(A, A)
fn:adjust-time-to-timezone(A, A)
fn:all-different(A, A)
fn:all-equal(A, A)
fn:analyze-string(A, A, A)
fn:apply(I, N)
fn:apply-templates(A, A)
fn:atomic-equal(A, A)
fn:atomic-type-annotation(A)
fn:available-environment-variables()
fn:available-system-properties()
fn:avg(A)
fn:base-uri(I)
fn:boolean(I)
fn:build-dateTime(A)
fn:build-uri(A, A)
fn:ceiling(A)
fn:char(A)
fn:character-map(A)
fn:characters(A)
fn:civil-timezone(A, A)
fn:codepoint-equal(A, A)
fn:codepoints-to-string(A)
fn:collation(A)
fn:collation-available(A, A)
fn:collation-key(A, A)
fn:collection(A)
fn:compare(A, A, A)
fn:concat(A)
fn:contains(A, A, A)
fn:contains-subsequence(T, T, A)
fn:contains-token(A, A, A)
fn:copy-of(A)
fn:count(I)
fn:csv-doc(A, A)
fn:csv-to-arrays(A, I)
fn:csv-to-xml(A, I)
fn:current – See 12.8.3 Streamability of the current Function
fn:current-date()
fn:current-dateTime()
fn:current-group – See 12.8.4 Streamability of the current-group Function
fn:current-grouping-key – See 12.8.5 Streamability of the current-grouping-key Function
fn:current-merge-group – See 12.8.6 Streamability of the current-merge-group Function
fn:current-merge-key – See 12.8.7 Streamability of the current-merge-key Function
fn:current-merge-key-array – See 12.8.8 Streamability of the current-merge-key-array Function
fn:current-output-uri()
fn:current-time()
fn:data(A)
fn:dateTime(A, A)
fn:day-from-date(A)
fn:day-from-dateTime(A)
fn:days-from-duration(A)
fn:decode-from-uri(A)
fn:deep-equal(A, A, A)
fn:default-collation()
fn:default-language()
fn:distinct-ordered-nodes – See 12.8.9 Streamability of the distinct-ordered-nodes Function
fn:distinct-values(A, A)
fn:divide-decimals(A, A, A)
fn:do-until(N, I, I)
fn:doc(A, A)
fn:doc-available(A, A)
fn:document(A, I)
fn:document-uri(I)
fn:duplicate-values(A, A)
fn:element-available(A)
fn:element-to-map(A, I)
fn:element-to-map-plan(A)
fn:element-with-id(A, N)
fn:empty(I)
fn:encode-for-uri(A)
fn:ends-with(A, A, A)
fn:ends-with-subsequence(T, T, A)
fn:environment-variable(A)
fn:error(A, A, N)
fn:escape-html-uri(A)
fn:every(N, I)
fn:exactly-one(I)
fn:exists(I)
fn:expanded-QName(A)
fn:false()
fn:filter(N, I)
fn:floor(A)
fn:fold-left(N, A, I)
fn:fold-right – See 12.8.11 Streamability of the fold-right Function
fn:foot – See 12.8.12 Streamability of the foot Function
fn:for-each(N, I)
fn:for-each-pair(N, N, I)
fn:format-date(A, A, A, A, A)
fn:format-dateTime(A, A, A, A, A)
fn:format-integer(A, A, A)
fn:format-number(A, A, A)
fn:format-time(A, A, A, A, A)
fn:function-annotations(A)
fn:function-arity(A)
fn:function-available(A, A)
fn:function-identity(A)
fn:function-lookup – See 12.8.15 Streamability of the function-lookup Function
fn:function-name(A)
fn:generate-id(I)
fn:graphemes(A)
fn:has-children(I)
fn:hash(A, A, A)
fn:head(T)
fn:highest(N, A, I)
fn:hours-from-dateTime(A)
fn:hours-from-duration(A)
fn:hours-from-time(A)
fn:html-doc(A, A)
fn:id(A, N)
fn:identity(T)
fn:idref(A, N)
fn:implicit-timezone()
fn:in-scope-namespaces(I)
fn:in-scope-prefixes(I)
fn:index-of(A, A, A)
fn:index-where(N, I)
fn:innermost – See 12.8.16 Streamability of the innermost Function
fn:insert-before(T, A, T)
fn:insert-separator(N, N)
fn:invisible-xml(N, A)
fn:iri-to-uri(A)
fn:is-NaN(A)
fn:items-at(T, A)
fn:jnode-content(A)
fn:jnode-position(I)
fn:jnode-selector(I)
fn:json-doc(A, I)
fn:json-to-xml(A, I)
fn:jtree(A)
fn:key(A, A, N)
fn:lang(A, I)
fn:last – See 12.8.17 Streamability of the last Function
fn:load-xquery-module(A, I)
fn:local-name(I)
fn:local-name-from-QName(A)
fn:lower-case(A)
fn:lowest(N, A, I)
fn:map-for-key(A, N)
fn:matches(A, A, A)
fn:max(A, A)
fn:message(T, 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(I)
fn:namespace-uri(I)
fn:namespace-uri-for-prefix(A, I)
fn:namespace-uri-from-QName(A)
fn:nilled(I)
fn:node-name(I)
fn:node-type-annotation(I)
fn:normalize-space(A)
fn:normalize-unicode(A, A)
fn:not(I)
fn:number(A)
fn:one-or-more(I)
fn:op(A)
fn:outermost – See 12.8.18 Streamability of the outermost Function
fn:parse-csv(A, I)
fn:parse-html(A, A)
fn:parse-ietf-date(A)
fn:parse-integer(A, A)
fn:parse-json(A, I)
fn:parse-QName(A)
fn:parse-uri(A, A)
fn:parse-xml(A, A)
fn:parse-xml-fragment(A, A)
fn:partial-apply(I, I)
fn:partition(N, I)
fn:parts-of-dateTime(A)
fn:path(N, A)
fn:position – See 12.8.19 Streamability of the position Function
fn:prefix-from-QName(A)
fn:QName(A, A)
fn:random-number-generator(A)
fn:regex-group(A)
fn:regex-groups()
fn:remove(T, A)
fn:replace(A, A, A, A)
fn:replicate(N, A)
fn:resolve-QName(A, I)
fn:resolve-uri(A, A)
fn:reverse – See 12.8.20 Streamability of the reverse Function
fn:root – See 12.8.21 Streamability of the root Function
fn:round(A, A, A)
fn:round-half-to-even(A, A)
fn:scan-left(N, N, I)
fn:scan-right(N, N, I)
fn:schema-type(A)
fn:seconds(A)
fn:seconds-from-dateTime(A)
fn:seconds-from-duration(A)
fn:seconds-from-time(A)
fn:serialize(A, A)
fn:siblings(N)
fn:slice(T, A, A, A)
fn:snapshot(A)
fn:some(N, I)
fn:sort(N, A, I)
fn:sort-by(N, A)
fn:sort-with(A, A)
fn:starts-with(A, A, A)
fn:starts-with-subsequence(T, T, A)
fn:static-base-uri()
fn:stream-available(A)
fn:string(A)
fn:string-join(A, A)
fn:string-length(A)
fn:string-to-codepoints(A)
fn:subsequence(T, A, A)
fn:subsequence-where(T, A, A)
fn:substring(A, A, A)
fn:substring-after(A, A, A)
fn:substring-before(A, A, A)
fn:sum(A, A)
fn:system-property(A)
fn:tail(T)
fn:take-while(N, I)
fn:timezone-from-date(A)
fn:timezone-from-dateTime(A)
fn:timezone-from-time(A)
fn:tokenize(A, A, A)
fn:trace(T, A)
fn:transform(I)
fn:transitive-closure(N, I)
fn:translate(A, A, A)
fn:true()
fn:trunk – See 12.8.22 Streamability of the trunk Function
fn:type-available(A)
fn:type-of(I)
fn:unix-dateTime(A)
fn:unordered(T)
fn:unparsed-binary(A)
fn:unparsed-entity-public-id(A, I)
fn:unparsed-entity-uri(A, I)
fn:unparsed-text(A, A)
fn:unparsed-text-available(A, A)
fn:unparsed-text-lines(A, A)
fn:upper-case(A)
fn:uri-collection(A)
fn:void(I)
fn:while-do(N, I, I)
fn:xml-to-json(A, I)
fn:xsd-validator(A)
fn:year-from-date(A)
fn:year-from-dateTime(A)
fn:years-from-duration(A)
fn:zero-or-one(I)
map:build(N, I, I, A)
map:contains(I, A)
map:empty(I)
map:entries(I)
map:entry(A, N)
map:filter(I, I)
map:find(I, A)
map:for-each(I, I)
map:get(I, A, T)
map:items(I)
map:keys(I)
map:keys-where(I, 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:cosh(A)
math:e()
math:exp(A)
math:exp10(A)
math:log(A)
math:log10(A)
math:pi()
math:pow(A, A)
math:sin(A)
math:sinh(A)
math:sqrt(A)
math:tan(A)
math:tanh(A)
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 patternXT 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 patternXT is grounded if the pattern is motionless, or roaming otherwise. (This reflects the fact that a pattern always returns a boolean result; it never returns a node in a streamed document.)
Informally, a motionless pattern is one that can be evaluated by a streaming processor when the input stream is positioned at the start of the node being matched, without advancing the input stream.
A pattern is motionless if and only if it satisfies all the following conditions:
The pattern does not contain a RootedPathXT.
If the pattern contains predicates, then every top-level Predicate in the pattern satisfies all the following conditions:
The expression immediately contained in the predicate is motionless, when assessed with a context posture of striding, and a context item type set to the static type of the expression to which the predicate applies, determined using the rules in 3.5 Determining the Static Type of a Construct.
The predicate is a non-positional predicate.
The use of the term top-level in this rule means that predicates that are nested within other predicates do not themselves have to be non-positional, though they may play a role in the analysis of top-level predicates.
The pattern does not contain (at any depth) a variable reference that is bound to a streaming parameter. (See 12.7.14 Streamability of Static Function Calls).
[[Definition: : A predicate is a non-positional predicate if it satisfies both of the following conditions:
The predicate does not contain a function call or named function reference to any of the following functions, unless that call or reference occurs within a nested predicate:
Note:
The exception for nested predicates is there to ensure that patterns such as match="p[@code = $status[last()]] are not disqualified.
The expression immediately contained in the predicate is a non-numeric expression. An expression is non-numeric if the intersection of its static type (see 3.5 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())
[[Definition: : A processor that claims conformance with the streaming featuremust use streamed processing in cases where (a) streaming is requested (for example by using the attribute streamable="yes" on xsl:mode, or on the xsl:source-document instruction) and (b) the constructs in question are guaranteed-streamable according to this specification.]
A processor that does not claim conformance with the streaming feature is not required to use streamed processing and is not required to determine whether any construct is guaranteed streamable. Such a processor must, however, implement the semantics of all constructs in the language provided that enough memory is available to perform the processing without streaming.
A processor that conforms with the feature must return the value "yes" in response to the function call system-property('xsl:supports-streaming'); a processor that does not conform with the feature must return the value "no".
Note:
The term streamed processing as used here means the ability to process arbitrarily large input documents without ever-increasing memory requirements.