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)
Copyright © 2026 W3C® (MIT, ERCIM, Keio, Beihang). W3C liability, trademark and document use rules apply.
This specification defines the syntax and semantics of XSLT 4.0, a language designed primarily for transforming XML documents into other XML documents, but also offering support for other data formats including JSON, HTML, and CSV.
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.
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.
The publications of this community group are dedicated to our co-chair, Michael Sperberg-McQueen (1954–2024).
[Definition: An error that can be detected by examining a stylesheet before execution starts (that is, before the source document and values of stylesheet parameters are available) is referred to as a static error.]
Generally, errors in the structure of the stylesheet, or in the syntax of XPath expressions contained in the stylesheet, are classified as static errors. Where this specification states that an element in the stylesheet must or must not appear in a certain position, or that it must or must not have a particular attribute, or that an attribute must or must not have a value satisfying specified conditions, then any contravention of this rule is a static error unless otherwise specified.
A processor must provide a mode of operation that takes a (possibly erroneous) stylesheet package as input and enables the user to determine whether or not that package contains any static errors.
Note:
The manner in which static errors are reported, and the behavior when there are multiple static errors, are left as design choices for the implementer. It is recommended that the error codes defined in this specification should be made available in any diagnostics.
A processor may also provide a mode of operation in which static errors in parts of the stylesheet that are not evaluated can go unreported.
Note:
For example, when operating in this mode, a processor might report static errors in a template rule only if the input document contains nodes that match that template rule. Such a mode of operation can provide performance benefits when large and well-tested stylesheets are used to process source documents that might only use a small part of the XML vocabulary that the stylesheet is designed to handle.
[Definition: An error that is not capable of detection until a source document is being transformed is referred to as a dynamic error.]
When a dynamic error occurs, and is not caught using xsl:catch, the processormust raise the error, and the transformation fails.
Because different implementations may optimize execution of the stylesheet in different ways, the detection of dynamic errors is to some degree implementation-dependent. In cases where an implementation is able to produce a principal result or secondary result without evaluating a particular construct, the implementation is never required to evaluate that construct solely in order to determine whether doing so causes a dynamic error. For example, if a variable is declared but never referenced, an implementation may choose whether or not to evaluate the variable declaration, which means that if evaluating the variable declaration causes a dynamic error, some implementations will raise this error and others will not.
There are some cases where this specification requires that a construct must not be evaluated: for example, the content of an xsl:if instruction must not be evaluated if the test condition is false. This means that an implementation must not raise any dynamic errors that would arise if the construct were evaluated.
An implementation may raise a dynamic error before any source document is available, but only if it can determine that the error would be raised for every possible source document and every possible set of parameter values. For example, some circularity errors fall into this category: see 9.11 Circular Definitions.
There are also some dynamic errors where the specification gives a processor license to raise the error during the analysis phase even if the construct might never be executed; an example is the use of an invalid QName as a literal argument to a function such as key, or the use of an invalid regular expression in the regex attribute of the xsl:analyze-string instruction.
A dynamic error is also raised during the static analysis phase if the error occurs during evaluation of a static expression.
The XPath specification states (see [XPath 4.0] section 2.4.1 Kinds of Errors) that if any expression (at any level) can be evaluated during the analysis phase (because all its explicit operands are known and it has no dependencies on the dynamic context), then any error in performing this evaluation may be raised as a static error. For XPath expressions used in an XSLT stylesheet, however, any such errors must not be raised as static errors in the stylesheet unless they would occur in every possible evaluation of that stylesheet; instead, they must be raised as dynamic errors, and raised only if the XPath expression is actually evaluated.
An XPath processor may report statically that the expression 1 div 0 fails with a “divide by zero” error. But suppose this XPath expression occurs in an XSLT construct such as:
<xsl:choose> <xsl:when test="system-property('xsl:version') = '1.0'"> <xsl:value-of select="1 div 0"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="xs:double('INF')"/> </xsl:otherwise> </xsl:choose>
Then the XSLT processor must not report an error, because the relevant XPath construct appears in a context where it will never be executed by an XSLT 4.0 processor. (An XSLT 1.0 processor will execute this code successfully, returning positive infinity, because it uses double arithmetic rather than decimal arithmetic.)
[Definition: Certain errors are classified as type errors. A type error occurs when the value supplied as input to an operation is of the wrong type for that operation, for example when an integer is supplied to an operation that expects a node.] If a type error occurs in an instruction that is actually evaluated, then it must be raised in the same way as a dynamic error. Alternatively, an implementation may raise a type error during the analysis phase in the same way as a static error, even if it occurs in part of the stylesheet that is never evaluated, provided it can establish that execution of a particular construct would never succeed.
It is implementation-defined whether type errors are raised statically.
The following construct contains a type error, because 42 is not allowed as the value of the select expression of the xsl:number instruction (it must be a node). An implementation may optionally raise this as a static error, even though the offending instruction will never be evaluated, and the type error would therefore never be raised as a dynamic error.
<xsl:if test="false()"> <xsl:number select="42"/> </xsl:if>
On the other hand, in the following example it is not possible to determine statically whether the operand of xsl:number will have a suitable dynamic type. An implementation may produce a warning in such cases, but it must not treat it as an error.
<xsl:template match="para"> <xsl:param name="p" as="item()"/> <xsl:number select="$p"/> </xsl:template>
If more than one error arises, an implementation is not required to raise any errors other than the first one that it detects. It is implementation-dependent which of the several errors is raised. This applies both to static errors and to dynamic errors. An implementation is allowed to raise more than one error, but if any errors have been raised, it must not finish as if the transformation were successful.
When a transformation raises one or more dynamic errors, the final state of any persistent resources updated by the transformation is implementation-dependent. Implementations are not required to restore such resources to their initial state. In particular, where a transformation produces multiple result documents, it is possible that one or more serialized result documents may be written successfully before the transformation terminates, but the application cannot rely on this behavior.
Everything said above about error handling applies equally to errors in evaluating XSLT instructions, and errors in evaluating XPath expressions. Static errors and dynamic errors may occur in both cases.
[Definition: If a transformation has successfully produced a principal result or secondary result, it is still possible that errors may occur in serializing that result . For example, it may be impossible to serialize the result using the encoding selected by the user. Such an error is referred to as a serialization error.] If the processor performs serialization, then it must do so as specified in 26 Serialization, and in particular it must raise any serialization errors that occur.
Errors are identified by a QName. For errors defined in this specification, the namespace of the QName is always http://www.w3.org/2005/xqt-errors (and is therefore not given explicitly), while the local part is an 8-character code in the form PPSSNNNN. Here PP is always XT (meaning XSLT), and SS is one of SE (static error), DE (dynamic error), or TE (type error). Note that the allocation of an error to one of these categories is purely for convenience and carries no normative implications about the way the error is handled. Many errors, for example, can be raised either dynamically or statically. These error codes are used to label error conditions in this specification, and are summarized in D Summary of Error Conditions.
Errors defined in related specifications ([XPath 4.0], [Functions and Operators 4.0][Serialization 4.0]) use QNames with a similar structure, in the same namespace. When errors occur in processing XPath expressions, an XSLT processor should use the original error code reported by the XPath processor, unless a more specific XSLT error code is available.
Implementations must use the codes defined in these specifications when raising dynamic errors, to ensure that xsl:catch behaves in an interoperable way across implementations. Stylesheet authors should note, however, that there are many examples of errors where more than one rule in this specification is violated, and where the processor therefore has discretion in deciding which error code to associate with the condition: there is therefore no guarantee that different processors will always use the same error code for the same erroneous input.
Additional errors defined by an implementation (or by an application) may use QNames in an implementation-defined (or user-defined) namespace without risk of collision.
The string value of an attribute or text node in the stylesheet may in particular circumstances contain embedded expressions enclosed between curly brackets. Attributes and text nodes that use (or are permitted to use) this mechanism are referred to respectively as attribute value templates and text value templates.
[Definition: Collectively, attribute value templates and text value templates are referred to as value templates.]
A value template is a string consisting of an alternating sequence of fixed parts and variable parts:
A variable part consists of an optional XPath expression enclosed in curly brackets ({}): more specifically, a string conforming to the XPath production Expr?.
Note:
An expression within a variable part may contain an unescaped curly bracket within a StringLiteralXP or within a comment.
Currently no XPath expression starts with an opening curly bracket, so the use of {{ creates no ambiguity. If an enclosed expression ends with a closing curly bracket, no whitespace is required between this and the closing delimiter.
The fact that the expression is optional means that the string contained between the curly brackets may be zero-length, may comprise whitespace only, or may contain XPath comments. The effective value in this case is a zero-length string, which is equivalent to omitting the variable part entirely, together with its curly-bracket delimiters.
A fixed part may contain any characters, except that a left curly bracket must be written as {{ and a right curly bracket must be written as }}.
[ERR XTSE0350] It is a static error if an unescaped left curly bracket appears in a fixed part of a value template without a matching right curly bracket.
It is a static error if the string contained between matching curly brackets in a value template does not match the XPath production Expr?XP, or if it contains other XPath static errors. The error is raised using the appropriate XPath error code.
[ERR XTSE0370] It is a static error if an unescaped right curly bracket occurs in a fixed part of a value template.
The result of evaluating a value template is referred to as its effective value. The effective value is the string obtained by concatenating the expansions of the fixed and variable parts:
The expansion of a fixed part is obtained by replacing any double curly brackets ({{ or }}) by the corresponding single curly bracket.
The expansion of a variable part is as follows:
If an expression is present, the result of evaluating the enclosed XPath expression and converting the resulting value to a string. This conversion is done using the rules given in 5.7.2 Constructing Simple Content.
If the expression is omitted, a zero-length string.
Note:
This process can raise dynamic errors, for example if the sequence contains an element with a complex content type (which cannot be atomized).
In the case of an attribute value template, the effective value becomes the string value of the new attribute node. In the case of a text value template, the effective value becomes the string value of the new text node.
The standard attribute[xsl:]expand-text may appear on any element in the stylesheet, and determines whether descendant text nodes of that element are treated as text value templates. A text node in the stylesheet is treated as a text value template if (a) it is part of a sequence constructor, (b) there is an ancestor element with an [xsl:]expand-text attribute, and (c) on the innermost ancestor element that has such an attribute, the value of the attribute is yes. The attribute is boolean and must therefore take one of the values yes (synonyms true or 1) or no (synonyms false or 0).
This section describes how text nodes are processed when the effective value is yes. Such text nodes are referred to as text value templates.
[Definition: In a text node that is designated as a text value template, expressions can be used by surrounding each expression with curly brackets ({}).]
The rules for text value templates are given in 5.6 Value Templates. A text node whose value is a text value template results in the construction of a text node in the result of the containing sequence constructor. The string value of that text node is obtained by computing the effective value of the value template.
Note:
The result of evaluating a text value template is a (possibly zero-length) text node. This text node becomes part of the result of the containing sequence constructor, and is thereafter handled exactly as if the value had appeared explicitly as a text node in the stylesheet.
The way in which the effective value is computed does not depend on any separator attribute on a containing xsl:text, xsl:value-of or xsl:attribute instruction. The separator attribute only affects how the text node is combined with adjacent items in the result of the containing sequence constructor.
Fixed parts consisting entirely of whitespace are significant and are handled in the same way as any other fixed part. This is different from the default treatment of “boundary space” in XQuery.
<xsl:variable name="id" select="'A123'"/> <xsl:variable name="step" select="5"/> <xsl:message expand-text="yes">Processing id={ $id }, step={ $step }</xsl:message>
This will typically output the message text Processing id=A123, step=5.
<xsl:function name="f:sum" expand-text="yes" as="xs:integer"> <xsl:param name="x" as="xs:integer"/> <xsl:param name="y" as="xs:integer"/> { $x + $y } </xsl:function>
Note that although this is a very readable way of expressing the computation performed by the function, the semantics are somewhat complex, and this could mean that execution is inefficient. The function computes the value of $x + $y as an integer, and then constructs a text node containing the string representation of this integer (preceded and followed by whitespace). Because the declared result type of the function is xs:integer, this text node is then atomized, giving an xs:untypedAtomic item, and the xs:untypedAtomic item is then cast to an xs:integer.
Note:
The main motivations for adding text value templates to the XSLT language are firstly, to make it easier to construct parameterized text in contexts such as xsl:text, xsl:value-of, and xsl:message, and secondly, to allow use of complex multi-line XPath expressions where maintaining correct indentation is important for readability. The fact that XML processors are required to normalize whitespace in attribute values means that writing such expressions within a select attribute is not ideal.
The facility is only present if enabled using the [xsl:]expand-text attribute. This is partly for backwards compatibility, and partly to avoid creating difficulties when constructing content that is rich in curly brackets, for example JavaScript code or CSS style sheets.
[Definition: A sequence constructor is a sequence of zero or more sibling nodes in the stylesheet that can be evaluated to return a sequence of nodes, atomic items, and function items. The way that the resulting sequence is used depends on the containing instruction.]
Many XSLT elements, and also literal result elements, are defined to take a sequence constructor as their content.
Four kinds of nodes may be encountered in a sequence constructor:
A Text node appearing in the stylesheet (if it has not been removed in the process of whitespace stripping: see 3.13.1 Stripping Whitespace and Commentary from the Stylesheet) is processed as follows:
if the effective value of the standard attribute [xsl:]expand-text is no, or in the absence of this attribute, the text node in the stylesheet is copied to create a new parentless text node in the result of the sequence constructor.
Otherwise (the effective value of [xsl:]expand-text is yes), the text node in the stylesheet is processed as described in 5.6.2 Text Value Templates.
A literal result element is evaluated to create a new parentless element node, having the same expanded QName as the literal result element: see 11.1 Literal Result Elements.
An XSLT instruction produces a sequence of zero, one, or more items as its result. For most XSLT instructions, these items are nodes, but some instructions (such as xsl:sequence, xsl:select, xsl:map, xsl:array, and xsl:copy-of) can also produce atomic items or function items.
Several instructions, such as xsl:element, return a newly constructed parentless node (which may have its own attributes, namespaces, children, and other descendants). Other instructions, such as xsl:if, pass on the items produced by their own nested sequence constructors.
Three instructions serve primarily to evaluate XPath expressions:
The xsl:sequence instruction evaluates an XPath expression written statically in its select attribute.
The xsl:select instruction evaluates an XPath expression written statically in its contained text node.
The xsl:evaluate instruction compiles and evaluates an XPath expression that is constructed dynamically as a character string.
These three instructions may return atomic items, function items, or nodes.
An extension instruction (see 24.2 Extension Instructions) also produces a sequence of items as its result.
[Definition: The result of evaluating a sequence constructor is the sequence of items formed by concatenating the results of evaluating each of the nodes in the sequence constructor, retaining order. This is referred to as the immediate result of the sequence constructor.]
However:
For the effect of the xsl:fallback instruction, see 24.2.3 Fallback.
For the effect of the xsl:on-empty and xsl:on-non-empty instructions, see 8.5 Conditional Content Construction.
The way that immediate result of a sequence constructor is used depends on the containing element in the stylesheet, and is specified in the rules for that element. It is typically one of the following:
The immediate result may be bound to a variable or delivered as the result of a stylesheet function. In this case the as attribute of the containing xsl:variable or xsl:function element may be used to declare its required type, and the immediate result is then converted to the required type by applying the coercion rules.
Note:
In the absence of an as attribute, the result of a function is the immediate result of the sequence constructor; but the value of a variable (for backwards compatibility reasons) is a document node whose content is formed by applying the rules in 5.7.1 Constructing Complex Content to the immediate result.
The coercion rules do not merge adjacent text nodes or insert separators between adjacent items. This means it is often inappropriate to use xsl:value-of in the body of xsl:variable or xsl:function, especially when the intent is to return an atomic result. The xsl:sequence instruction is designed for this purpose, and is usually a better choice.
The result of a function, or the value of a variable, may contain nodes (such as elements, attributes, and text nodes) that are not attached to any parent node in a result tree. The semantics of XPath expressions when applied to parentless nodes are well-defined; however, such expressions should be used with care. For example, the expression / causes a type error if the root of the tree containing the context node is not a document node.
Parentless attribute nodes require particular care because they have no namespace nodes associated with them. A parentless attribute node is not permitted to contain namespace-sensitive content (for example, a QName or an XPath expression) because there is no information enabling the prefix to be resolved to a namespace URI. Parentless attributes can be useful in an application (for example, they provide an alternative to the use of attribute sets: see 10.2 Named Attribute Sets) but they need to be handled with care.
The sequence may be returned as the result of the containing element. This happens, for example, when the element containing the sequence constructor is xsl:break, xsl:catch, xsl:fallback, xsl:for-each, xsl:for-each-group, xsl:fork, xsl:if, xsl:iterate, xsl:matching-substring, xsl:non-matching-substring, xsl:on-completion, xsl:otherwise, xsl:perform-sort, xsl:sequence, xsl:try, or xsl:when.
The sequence may be used to construct the content of a new element or document node. This happens when the sequence constructor appears as the content of a literal result element, or of one of the instructions xsl:copy, xsl:element, xsl:document, xsl:result-document, xsl:assert, or xsl:message. It also happens when the sequence constructor is contained in one of the elements xsl:variable, xsl:param, or xsl:with-param, when this instruction has no as attribute. For details, see 5.7.1 Constructing Complex Content.
The sequence may be used to construct the string value of an attribute node, text node, namespace node, comment node, or processing instruction node. This happens when the sequence constructor is contained in one of the elements xsl:attribute, xsl:text, xsl:value-of, xsl:namespace, xsl:comment, or xsl:processing-instruction. For details, see 5.7.2 Constructing Simple Content.
The instructions xsl:attribute, xsl:comment, xsl:processing-instruction, xsl:namespace, xsl:text, and xsl:value-of all create nodes that cannot have children. Specifically, the xsl:attribute instruction creates an attribute node, xsl:comment creates a comment node, xsl:processing-instruction creates a processing instruction node, xsl:namespace creates a namespace node, and xsl:text and xsl:value-of creates a text nodecreate text nodes. The string value of the new node is constructed using either the select attribute of the instruction, or the sequence constructor that forms the content of the instruction. The select attribute allows the content to be specified by means of an XPath expression, while the sequence constructor allows it to be specified by means of a sequence of XSLT instructions. The select attribute or sequence constructor is evaluated to produce a result sequence, and the string value of the new node is derived from this result sequence according to the rules below.
These rules are also used to compute the effective value of a value template. In this case the sequence being processed is the result of evaluating an XPath expression enclosed between curly brackets, and the separator is a single space character.
Zero-length text nodes in the sequence are discarded.
Adjacent text nodes in the sequence are merged into a single text node.
The sequence is atomized (which may cause a dynamic error).
Every value in the atomized sequence is cast to a string.
The strings within the resulting sequence are concatenated, with a (possibly zero-length) separator inserted between successive strings. The default separator depends on the containing instruction; except where otherwise specified, it is a single space.
In the case of xsl:attribute, xsl:text, and xsl:value-of, the default separator is a single space when the select attribute is used, or a zero-length string otherwise; a different separator can be specified using the separator attribute of the instruction.
In the case of xsl:comment, xsl:processing-instruction, and xsl:namespace, and when expanding a value template, the default separator cannot be changed.
In the case of xsl:processing-instruction, any leading spaces in the resulting string are removed.
The resulting string forms the string value of the new attribute, namespace, comment, processing-instruction, or text node.
Consider the following stylesheet fragment:
<doc> <xsl:attribute name="e" select="1 to 5"/> <xsl:attribute name="f"> <xsl:for-each select="1 to 5"> <xsl:value-of select="."/> </xsl:for-each> </xsl:attribute> <xsl:attribute name="g" expand-text="yes">{1 to 5}</xsl:attribute> </doc>
This produces the output:
<doc e="1 2 3 4 5" f="12345" g="1 2 3 4 5"/>
The difference between the three cases is as follows. For the e attribute, the sequence constructor generates a sequence of five atomic items, which are therefore separated by spaces. For the f attribute, the content is supplied as a sequence of five text nodes, which are concatenated without space separation. For the g attribute, the text value template constructs a text node using the rules for constructing simple content, which insert space separators between atomic items; the text node is then atomized to form the value of the attribute.
Specifying separator="" on the first xsl:attribute instruction would cause the attribute value to be e="12345". A separator attribute on the second xsl:attribute instruction would have no effect, since the separator only affects the way adjacent atomic items are handled: separators are never inserted between adjacent text nodes. A separator on the third xsl:attribute instruction would also have no effect, because text value templates are evaluated without regard to the containing instruction.
Note:
If an attribute value template contains a sequence of fixed and variable parts, no additional whitespace is inserted between the expansions of the fixed and variable parts. For example, the effective value of the attribute a="chapters{4 to 6}" is a="chapters4 5 6".
There are several instructions in XSLT that support conditional processing: xsl:if, xsl:choose, and xsl:switch. The xsl:if instruction provides simple if-then-else conditionality; the xsl:choose instruction supports selection of one choice when there are several possibilities, and xsl:switch allows a branch to be selected based on the value of a given expression.
XSLT 3.0 also supports xsl:try and xsl:catch which define conditional processing to handle dynamic errors.
Note:
XSLT offers a number of ways of expressing conditional logic.
XSLT 1.0 offered the xsl:if instruction for cases where output was to be produced only if a condition was true, with xsl:choose available for multi-way branches where different output was to be produced under different input conditions. In addition, of course, XSLT 1.0 also offered the option of rule-based processing using templates and match patterns.
XSLT 2.0 added the XPath conditional expression providing two-way branches for use at a finer-grained level where xsl:choose could be excessively verbose: it allowed constructs such as <xsl:value-of select="if ($x) then 'red' else 'green'/> to be reduced from eight lines of code to one.
XSLT 4.0 introduces the then and else attributes for xsl:if, which are particularly useful in contexts such as the body of an xsl:function declaration where the alternative results are conveniently evaluated using XPath expressions rather than XSLT instructions: for example a recursive function might have as its body the instruction <xsl:if test="empty($seq)" then="1" else="head($seq) * my:f(tail($seq))"/>. The select attribute of xsl:when and xsl:otherwise is introduced for similar reasons: XSLT instructions are most useful when contructing node trees, whereas XPath expressions are more convenient when computing atomic items. Again, the main contribution of these enhancements is to reduce visual clutter, making the code more concise and more easily readable.
The xsl:switch instruction is introduced in XSLT 4.0 as an alternative to xsl:choose for the common use case where the conditions test for multiple different values of some common expression. By avoiding repetition of the common expression whose value is being tested, the logic becomes self-explanatory both to the human reader of the code and to an optimizing compiler, making it easier to generate efficient branching code.
The facilities described in this section are designed to make it easier to generate result trees conditionally depending on what is found in the input, without violating the rules for streamability. These facilities are available whether or not streaming is in use, but they are introduced to the language specifically to make streaming easier.
The facilities are introduced first by example:
The following example generates an events element if and only if there are one or more event elements. The code could be written like this:
<xsl:if test="exists(event)"> <events> <xsl:copy-of select="event"/> </events> </xsl:if>
However, the above code would not be guaranteed-streamable, because it processes the child event elements more than once. To make it streamable, it can be rewritten as:
<xsl:where-populated> <events> <xsl:copy-of select="event"/> </events> </xsl:where-populated>
The effect of the xsl:where-populated instruction, as explained later, is to avoid outputting the events element if it would have no children. A streaming implementation will typically hold the start tag of the events element in a buffer, to be sent to the output destination only if and when a child node is generated.
The following example generates an h3 element and a summary paragraph only if a list of items is non-empty. The code could be written like this:
<xsl:if test="exists(item-for-sale)"> <h1>Items for Sale</h1> </xsl:if> <xsl:apply-templates select="item-for-sale"/> <xsl:if test="exists(item-for-sale)"> <p>Total value: {accumulator-before('total-value')}</p> </xsl:if>
However, the above code would not be guaranteed-streamable, because it processes the child item-for-sale elements more than once. To make it streamable, it can be rewritten as:
<xsl:sequence> <xsl:on-non-empty> <h1>Items for Sale</h1> </xsl:on-non-empty> <xsl:apply-templates select="item-for-sale"/> <xsl:on-non-empty> <p>Total value: {accumulator-before('total-value')}</p> </xsl:on-non-empty> </xsl:sequence>
The effect of the xsl:on-non-empty instruction, as explained later, is to output the enclosed content only if the containing sequence constructor also generates “ordinary” content, that is, if there is content generated by instructions other than xsl:on-empty and xsl:on-non-empty instructions.
The following example generates a summary paragraph only if a list of items is empty. The code could be written like this:
<xsl:apply-templates select="item-for-sale"/> <xsl:if test="empty(item-for-sale)"> <p>There are no items for sale.</p> </xsl:if>
However, the above code would not be guaranteed-streamable, because it processes the child item-for-sale elements more than once (the fact that the list is empty is irrelevant, because streamability is determined statically). To make the code streamable, it can be rewritten as:
<xsl:sequence> <xsl:apply-templates select="item-for-sale"/> <xsl:on-empty> <p>There are no items for sale.</p> </xsl:on-empty> </xsl:sequence>
The effect of the xsl:on-empty instruction, as explained later, is to output the enclosed content only if the containing sequence constructor generates no “ordinary” content, that is, if there is no content generated by instructions other than xsl:on-empty and xsl:on-non-empty instructions.
Note:
In some cases, similar effects can be achieved by using the has-children function, which tests whether an element has child nodes without consuming the children. However, use of has-children has the drawback that the function is unselective: it cannot be used to test whether there are any children of relevance to the application. In particular, it returns true if an element contains comments or whitespace text nodes that the application might consider to be insignificant.
Note:
There are no special streamability rules for the three instructions xsl:where-populated, xsl:on-empty, or xsl:on-non-empty. The general streamability rules apply. In many cases the xsl:on-empty and xsl:on-non-empty instructions will generate content that does not depend on the source document, and they will therefore be motionless, but this is not required.
xsl:where-populated instruction<!-- Category: instruction -->
<xsl:where-populated>
<!-- Content: sequence-constructor -->
</xsl:where-populated>
The xsl:where-populated instruction encloses a sequence constructor. The result of the instruction is established as follows:
The sequence constructor is evaluated in the usual way (taking into account any xsl:on-empty and xsl:on-non-empty instructions) to produce a result $R.
The result of the instruction is the value of the expression $R[not(deemed-empty(.))] where the function deemed-empty($item as item()) returns true if and only if $item is one of the following:
A document or element node that has no children.
Note:
If an element has attributes or namespaces, these do not prevent the element being deemed empty.
If a document or element node has children, the node is not deemed empty, even if the children are empty. For example, a document node created using an xsl:variable instruction in the form <xsl:variable name="temp"><a/></xsl:variable> is not deemed empty, even though the contained <a/> element is empty.
A node, other than a document or element node, whose string value is zero-length.
Note:
A whitespace-only text node is not deemed empty.
An atomic item such that the result of casting the atomic item to a string is zero-length.
Note:
This can happen only when the atomic item is of type xs:string, xs:anyURI, xs:untypedAtomic, xs:hexBinary, or xs:base64Binary.
A map whose size (number of key/value pairs) is zero.
An array (see 22 Arrays) where the result of flattening the array using the array:flatten function is either an empty sequence, or a sequence in which every item is deemed empty (applying these rules recursively).
The following example generates an HTML unnumbered list, if and only if the list is non-empty. Note that the presence of the class attribute does not make the list non-empty. The code is written to be streamable.
<xsl:where-populated expand-text="yes"> <ul class="my-list"> <xsl:for-each select="source-item"> <li>{<xsl:value-of select="."}/></li> </xsl:for-each> </ul> </xsl:where-populated>
This example shows how the three instructions xsl:where-populated, xsl:on-empty, and xsl:on-non-empty may be combined.
The following example generates a table containing the names and ages of a set of students; if there are no students, it substitutes a paragraph explaining this.
<div id="students" xsl:expand-text="yes"> <xsl:where-populated> <table> <xsl:on-non-empty> <thead> <tr><th>Name</th><th>Age</th></tr> </thead> </xsl:on-non-empty> <xsl:where-populated> <tbody> <xsl:for-each select="student/copy-of()"> <tr> <td>{<xsl:value-of select="name"}/></td> <td>{<xsl:value-of select="age"}/></td> </tr> </xsl:for-each> </tbody> </xsl:where-populated> </table> </xsl:where-populated> <xsl:on-empty> <p>There are no students</p> </xsl:on-empty> </div>
Explanation:
The xsl:where-populated around the table element ensures that if there is no thead and no tbody, then there will be no table.
The xsl:on-non-empty surrounding the thead element ensures that the thead element is not output unless the tbody element is output.
The xsl:where-populated around the tbody element ensures that the tbody element is not output unless there is at least one table row (tr).
The xsl:on-empty around the p element ensures that if no table is output, then the paragraph There are no students is output instead.
This section describes three constructs that can be used to provide subroutine-like functionality that can be invoked from anywhere in the stylesheet: named templates (see 10.1 Named Templates), named attribute sets (see 10.2 Named Attribute Sets), and stylesheet functions (see 10.3 Stylesheet Functions).
[Definition: The following constructs are classified as invocation constructs: the instructions xsl:call-template, xsl:apply-templates, xsl:apply-imports, and xsl:next-match; XPath function calls that bind to stylesheet functions; XPath dynamic function calls; the functions accumulator-before and accumulator-after; the [xsl:]use-attribute-sets attribute. These all have the characteristic that they can cause evaluation of constructs that are not lexically contained within the calling construct.]
Parameters on functions declared using xsl:function can now be defined as optional, with a default value supplied. [Issue 155 PR 159 30 September 2022]
User-defined functions can now have names that are in no namespace. An unprefixed name appearing in a function call is resolved to a no-namespace function with matching local name in preference to a function in the standard fn namespace. [Issue 657 ]
[Definition: An xsl:function declaration declares the name, parameters, and implementation of a family of stylesheet functions that can be called from any XPath expression within the stylesheet (subject to visibility rules).]
<!-- Category: declaration -->
<xsl:function
name = eqname
as? = sequence-type〔'item()*'〕
visibility? = "public" | "private" | "final" | "abstract"〔'private'〕
streamability? = "unclassified" | "absorbing" | "inspection" | "filter" | "shallow-descent" | "deep-descent" | "ascent" | eqname〔'unclassified'〕
override-extension-function? = boolean〔'yes'〕
[override]? = boolean〔'yes'〕
new-each-time? = "yes" | "true" | "1" | "no" | "false" | "0" | "maybe"
cache? = boolean〔'no'〕 >
<!-- Content: (xsl:param*, sequence-constructor) -->
</xsl:function>
The effect of an xsl:function declaration is to add a function definition to the static context for all XPath expressions used in the stylesheet (including an XPath expression used within a predicate in a pattern).
The content of the xsl:function element consists of zero or more xsl:param elements that specify the formal parameters of the function, followed by a sequence constructor that defines the value to be returned by the function.
The children and attributes of the xsl:function declaration translate directly into properties of the function definition:
The xsl:function/@name attribute defines the function’s name.
The xsl:param children define the function’s parameters:
The xsl:param/@name attribute defines the name of the parameter.
The xsl:param/@required attribute determines whether the parameter is mandatory or optional.
The xsl:param/@as attribute determines the required type of the parameter.
The xsl:param/@select attribute determines a default value for an optional parameter.
The xsl:function/@as attribute defines the return type of the function.
The implementation of the function is defined by the sequence constructor content of the xsl:function element.
An xsl:function declaration can only appear as a top-level element in a stylesheet module.
The following example creates a recursive stylesheet function named str:reverse that reverses the words in a supplied sentence, and then invokes this function from within a template rule.
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:str="http://example.com/namespace" version="3.0" expand-text="yes" exclude-result-prefixes="str"> <xsl:function name="str:reverse" as="string"> <xsl:param name="sentence" as="string"/> <xsl:sequencexsl:if selecttest="if (contains($sentence, ' '))" then =concat"(str:reverse(substring-after($sentence, ' ')) || ' ' || substring-before($sentence, ' ')str:reverse"(substring-after($sentence, ' ')), ' ', substring-before($sentence, ' ')) else ="$sentence"/> </xsl:function> <xsl:template match="/"> <output> {<xsl:value-of select="str:reverse('DOG BITES MAN')"}/> </output> </xsl:template> </xsl:transform>
An alternative way of writing the same function is to implement the conditional logic at the XSLT level, thus:
<xsl:function name="str:reverse" as="xs:string"> <xsl:param name="sentence" as="string"/> <xsl:if test="contains($sentence, ' ')" then="concat(str:reverse(substring-after($sentence, ' ')), ' ', substring-before($sentence, ' '))" else="$sentence"/> </xsl:function>
The following example illustrates the use of the as attribute in a function definition. It returns a string containing the representation of its integer argument, expressed as a roman numeral. For example, the function call num:roman(7) will return the string "vii". This example uses the xsl:number instruction, described in 12 Numbering. The xsl:number instruction returns a text node, and the coercion rules are invoked to convert this text node to the type declared in the xsl:function element, namely xs:string. So the text node is atomized to a string.
<xsl:function name="num:roman" as="xs:string"> <xsl:param name="value" as="xs:integer"/> <xsl:number value="$value" format="i"/> </xsl:function>
XPath 3.0 introduces the ability to pass function items as arguments to a function. A function that takes function items as arguments is known as a higher-order function.
The following example is a higher-order function that operates on any tree-structured data, for example an organization chart. Given as input a function that finds the direct subordinates of a node in this tree structure (for example, the direct reports of a manager, or the geographical subdivisions of an administrative area), it determines whether one object is present in the subtree rooted at another object (for example, whether one person is among the staff managed directly or indirectly by a manager, or whether one parcel of land is contained directly or indirectly within another parcel). The function does not check for cycles in the data.
<xsl:function name="f:is-subordinate" as="xs:boolean"> <xsl:param name="superior" as="node()"/> <xsl:param name="subordinate" as="node()"/> <xsl:param name="get-direct-children" as="fn(node()) as node()*"/> <xsl:select> some $sub in $get-direct-children($superior) satisfies ($sub is $subordinate or f:is-subordinate($sub, $subordinate, $get-direct-children)) </xsl:select> </xsl:function>
(This example is written to use the xsl:select instruction, newly introduced in XSLT 4.0, to compute the function result.)
Given source data representing an organization chart in the form of elements such as:
<employee id="P57832" manager="P68951"/>
the following function can be defined to get the direct reports of a manager:
<xsl:function name="f:direct-reports" as="element(employee)*"> <xsl:param name="manager" as="element(employee)"/> <xsl:sequence select="$manager/../employee [@manager = $manager/@id]"/> </xsl:function>
It is then possible to test whether one employee $E reports directly or indirectly to another employee $M by means of the function call:
f:is-subordinate($M, $E, f:direct-reports#1)
The two instructions described in this section, xsl:sequence and xsl:select, can be used to evaluate XPath expressions that are statically known: that is, the XPath expressions are statically processed during the static processing of the stylesheet, and are dynamically evaluated during the dynamic evaluation of the stylesheet. The xsl:sequence instruction can also be used to evaluate a sequence constructor.
xsl:select Instruction The xsl:select instruction is new in 4.0. [Issue 2004 PR 2008 20 May 2025]
<!-- Category: instruction -->
<xsl:select
as? = sequence-type〔'item()*'〕 >
<!-- Content: (xsl:fallback*#PCDATA) -->
</xsl:select>
The xsl:select instruction evaluates an XPath expression contained as a child node of the instruction. For example, the instruction:
<xsl:select as="map(*)"> { "title" : $title, "author" : $author } </xsl:select>
evaluates the contained XPath expression, in the current static and dynamic context, and returns (in this example) a map with two entries.
While the xsl:sequence instruction (with a select attribute) can also be used to evaluate an arbitrary XPath expression and return its result, the xsl:select instruction offers some potential advantages:
An XPath expression written within an XML attribute is subjected by the XML parser to attribute value normalization, which changes the arrangement of whitespace within the value. While this will rarely affect the actual meaning of the expression, it can mean that formatting is lost. Multi-line attribute values are therefore best avoided. The loss of formatting also makes it difficult for an XSLT processor to provide precise error locations.
When an XPath expression appears in an attribute value, then one of the characters U+0022 (QUOTATION MARK, ") or U+0027 (APOSTROPHE, ') becomes unavailable for use with the expression, unless written as " or ' respectively. When an expression is written within a text node, this problem does not arise, and both characters can be used without escaping.
The content of the xsl:select instruction can be written as a CDATA section, allowing operators such as < and <= to be written without escaping.
The instruction name xsl:sequence can easily confuse people reading the code in cases where the intent is to return a single item.
With the increasing richness of the XPath language, expressions of ten or twenty lines become increasingly common, and this instruction makes such expressions more manageable. This often arises when constructing maps and arrays designed to be serialized as JSON. For example, a function might be defined that takes an element node as input and constructs a map containing selected information:
<xsl:function name="f:book-to-json" as="map(*)"> <xsl:param name="book" as="element(book)"> <xsl:select> { "title" : string($book/title), "isbn" : string($book/isbn), "price" : number($book/@price), "author" : array { $book/author ! string() }, "date" : current-date()" } </xsl:select> </xsl:function>
Any xsl:fallback child instructions will be ignored by an XSLT 4.0 processor, but will be evaluated by an XSLT 3.0 or earlier processor running in forwards compatible mode. An xsl:fallback instruction may be preceded by a text node consisting entirely of whitespace, but must not be preceded by a text node containing non-whitespace characters. The XPath expression to be evaluated is therefore contained in the last text node child. (XML comments, processing instructions, and xsl:note elements will already have been removed.)
The effect of the xsl:select instruction is as follows:
Let E be the string value of the last text node child of the instruction, if any.
If E is absent, zero-length, or consists entirely of whitespace, then let V be the empty sequence.
Otherwise, let V be the result of evaluating E as an XPath expression in the current static and dynamic context.
The result of the xsl:select instruction is the result of using the coercion rules to convert V to the type appearing in the as attribute, defaulting to item()*.
Note:
The text node cannot contain text value templates.
Note:
The xsl:select instruction requires the XPath expression to be known statically (though it can refer to variables whose value is dynamic). The xsl:evaluate instruction, by contrast, can be used to evaluate XPath expressions that are constructed dynamically or read from an external document. The xsl:evaluate instruction is described in the next section.
Note:
Many instructions take their input either from an XPath expression contained in a select attribute, or from a sequence constructor forming the content of the instruction, the two options being mutually exclusive. Instructions that follow this pattern include xsl:break, xsl:on-completion, xsl:catch, xsl:on-empty, xsl:when, xsl:attribute, and many others. In most of these cases, writing an XPath expression within a child xsl:select element is equivalent to writing the same expression with a select attribute. However, there are a few subtle differences, for example in the case of xsl:attribute, xsl:text, and xsl:value-of, the default separator is different (a single space when a select attribute is used, a zero-length string for a sequence constructor comprising an xsl:select instruction).
A new attribute xsl:for-each-group/@split-when is available to give applications more complete control over how a sequence is partitioned [Issue 571 26 September 2023]
A new attribute xsl:for-each-group/@merge-when is available to give applications control to create groups based on clustering, overlap, and networks. [Issue 2051 23 July 2025]
The facilities described in this section are designed to allow items in a sequence to be grouped based on common values; for example it allows grouping of elements having the same value for a particular attribute, or elements with the same name, or elements with common values for any other expression. Since grouping identifies items with duplicate values, the same facilities also allow selection of the distinct values in a sequence of items, that is, the elimination of duplicates.
Note:
Simple elimination of duplicates can also be achieved using the function distinct-values: see [Functions and Operators 4.0].
In addition these facilities allow grouping based on sequential position, for example selecting groups of adjacent para elements. The facilities also provide an easy way to do fixed-size grouping, for example identifying groups of three adjacent nodes, which is useful when arranging data in multiple columns.
For each group of items identified, it is possible to evaluate a sequence constructor for the group. Grouping is nestable to multiple levels so that groups of distinct items can be identified, then from among the distinct groups selected, further sub-grouping of distinct items in the current group can be done.
It is also possible for one item to participate in more than one group.
Note:
Grouping can also be achieved by constructing a map. For example, the function call map:build(//employee, fn { department }) constructs a map in which employees are grouped by department.
The following example groups a list of nodes based on common values. The resulting groups are numbered and sorted, and a total is calculated for each group.
Source XML document:
<cities> <city name="Milano" country="Italia" pop="5"/> <city name="Paris" country="France" pop="7"/> <city name="München" country="Deutschland" pop="4"/> <city name="Lyon" country="France" pop="2"/> <city name="Venezia" country="Italia" pop="1"/> </cities>
More specifically, the aim is to produce a four-column table, containing one row for each distinct country. The four columns are to contain first, a sequence number giving the number of the row; second, the name of the country, third, a comma-separated alphabetical list of the city names within that country, and fourth, the sum of the pop attribute for the cities in that country.
Desired output:
<table> <tr> <th>Position</th> <th>Country</th> <th>List of Cities</th> <th>Population</th> </tr> <tr> <td>1</td> <td>Italia</td> <td>Milano, Venezia</td> <td>6</td> </tr> <tr> <td>2</td> <td>France</td> <td>Lyon, Paris</td> <td>9</td> </tr> <tr> <td>3</td> <td>Deutschland</td> <td>München</td> <td>4</td> </tr> </table>
Solution:
<table xsl:version="3.0" xsl:expand-text="yes" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <tr> <th>Position</th> <th>Country</th> <th>City List</th> <th>Population</th> </tr> <xsl:for-each-group select="cities/city" group-by="@country"> <tr> <td>{<xsl:value-of select="position()"}/></td> <td>{<xsl:value-of select="current-grouping-key()"}/></td> <td> <xsl:for-each select="current-group()/@name"> <xsl:sort select="."/> <xsl:if test="position() ne 1">, </xsl:if> <{xsl:value-of select="."}/> </xsl:for-each> </td> <td>{<xsl:value-of select="sum(current-group()/@pop)"}/></td> </tr> </xsl:for-each-group> </table>
Sometimes it is necessary to use a composite grouping key: for example, suppose the source document is similar to the one used in the previous examples, but allows multiple entries for the same country and city, such as:
<cities> <city name="Milano" country="Italia" year="1950" pop="5.23"/> <city name="Milano" country="Italia" year="1960" pop="5.29"/> <city name="Padova" country="Italia" year="1950" pop="0.69"/> <city name="Padova" country="Italia" year="1960" pop="0.93"/> <city name="Paris" country="France" year="1951" pop="7.2"/> <city name="Paris" country="France" year="1961" pop="7.6"/> </cities>
Now suppose we want to list the average value of @pop for each (country, name) combination. One way to handle this is to concatenate the parts of the key, for example <xsl:for-each-group select="concat(@country, '/', @name)">. A second solution is to nest one xsl:for-each-group element directly inside another. XSLT 3.0 introduces a third option, which is to define the grouping key as composite:
<xsl:for-each-group select="cities/city" group-bygroup -by="@@name, @countryname", composite@=country"yes" compositeexpand-text="yes"> <p> {<xsl:value-of select="current-grouping-key()[1] }||, '{, ' || current-grouping-key()[2] }||: '{avg(current-group()/@pop)": '" <t>||{ current-grouping-key()[1]}, {current-grouping-key()[2]}: {avg(current-group()/@pop)"/>/> </p> </xsl:for-each-group>
Note:
The string concatenation operator || is new in XPath 3.0.
The next example identifies a group not by the presence of a common value, but rather by adjacency in document order. A group consists of an h2 element, followed by all the p elements up to the next h2 element.
Source XML document:
<body> <h2>Introduction</h2> <p>XSLT is used to write stylesheets.</p> <p>XQuery is used to query XML databases.</p> <h2>What is a stylesheet?</h2> <p>A stylesheet is an XML document used to define a transformation.</p> <p>Stylesheets may be written in XSLT.</p> <p>XSLT 2.0 introduces new grouping constructs.</p> </body>
Desired output:
<chapter> <section title="Introduction"> <para>XSLT is used to write stylesheets.</para> <para>XQuery is used to query XML databases.</para> </section> <section title="What is a stylesheet?"> <para>A stylesheet is used to define a transformation.</para> <para>Stylesheets may be written in XSLT.</para> <para>XSLT 2.0 introduces new grouping constructs.</para> </section> </chapter>
Solution:
<xsl:template match="body"> <chapter> <xsl:for-each-group select="*" group-starting-with="h2"> <section title="{self::h2}"> <xsl:for-each select="current-group()[self::p]"> <para><xsl:value-of select="."/></para> </xsl:for-each> </section> </xsl:for-each-group> </chapter> </xsl:template>
The use of title="{self::h2}" rather than title="{.}" is to handle the case where the first element is not an h2 element.
The next example illustrates how a group of related elements can be identified by the last element in the group, rather than the first. Here the absence of the attribute continued="yes" indicates the end of the group.
Source XML document:
<doc> <page continued="yes">Some text</page> <page continued="yes">More text</page> <page>Yet more text</page> <page continued="yes">Some words</page> <page continued="yes">More words</page> <page>Yet more words</page> </doc>
Desired output:
<doc> <pageset> <page>Some text</page> <page>More text</page> <page>Yet more text</page> </pageset> <pageset> <page>Some words</page> <page>More words</page> <page>Yet more words</page> </pageset> </doc>
Solution:
<xsl:template match="doc"> <doc> <xsl:for-each-group select="*" group-ending-with="page[not(@continued='yes')]"> <pageset> <xsl:for-each select="current-group()"> <page><xsl:value-of select="."/></page> </xsl:for-each> </pageset> </xsl:for-each-group> </doc> </xsl:template>
The next example shows how an item can be added to multiple groups. Book titles will be added to one group for each indexing term marked up within the title.
Source XML document:
<titles> <title>A Beginner's Guide to <ix>Java</ix></title> <title>Learning <ix>XML</ix></title> <title>Using <ix>XML</ix> with <ix>Java</ix></title> </titles>
Desired output:
<h2>Java</h2> <p>A Beginner's Guide to Java</p> <p>Using XML with Java</p> <h2>XML</h2> <p>Learning XML</p> <p>Using XML with Java</p>
Solution:
<xsl:template match="titles"> <xsl:for-each-group select="title" group-by="ix"> <h2><xsl:value-of select="current-grouping-key()"/></h2> <xsl:for-each select="current-group()"> <p><xsl:value-of select="."/></p> </xsl:for-each> </xsl:for-each-group> </xsl:template>
In this example, the membership of a node within a group is based both on adjacency of the nodes in document order, and on common values. In this case, the grouping key is a boolean condition, true or false, so the effect is that a grouping establishes a maximal sequence of nodes for which the condition is true, followed by a maximal sequence for which it is false, and so on.
Source XML document:
<p>Do <em>not</em>: <ul> <li>talk,</li> <li>eat, or</li> <li>use your mobile telephone</li> </ul> while you are in the cinema.</p>
Desired output:
<p>Do <em>not</em>:</p> <ul> <li>talk,</li> <li>eat, or</li> <li>use your mobile telephone</li> </ul> <p>while you are in the cinema.</p>
Solution:
This requires creating a p element around the maximal sequence of sibling nodes that does not include a ul or ol element.
This can be done by using group-adjacent, with a grouping key that is true if the element is a ul or ol element, and false otherwise:
<xsl:template match="p"> <xsl:for-each-group select="node()" group-adjacent="self::ul or self::ol"> <xsl:choose> <xsl:when test="current-grouping-key()"> <xsl:copy-of select="current-group()"/> </xsl:when> <xsl:otherwise> <p> <xsl:copy-of select="current-group()"/> </p> </xsl:otherwise> </xsl:choose> </xsl:for-each-group> </xsl:template>
Consider a map with composite keys that might appear in a JSON document as:
{
"Africa/Abidjan": { "offset": "+00:00", "DST-offset": "+00:00" },
"Africa/Algiers": { "offset": "+01:00", "DST-offset": "+01:00" },
"Africa/Nairobi": { "offset": "+03:00", "DST-offset": "+03:00" },
"America/Anchorage": { "offset": "-09:00", "DST-offset": "-08:00" },
"America/Los_Angeles": { "offset": "-08:00", "DST-offset": "-07:00" },
"Asia/Dubai": { "offset": "+04:00", "DST-offset": "+04:00" },
"Asia/Kolkata": { "offset": "+05:30", "DST-offset": "+05:30" }
}And suppose we wish to group this into a two-level map, thus:
{
"Africa": {
"Abidjan": { "offset": "+00:00", "DST-offset": "+00:00" },
"Algiers": { "offset": "+01:00", "DST-offset": "+01:00" },
"Nairobi": { "offset": "+03:00", "DST-offset": "+03:00" }
},
"America": {
"Anchorage": { "offset": "-09:00", "DST-offset": "-08:00" },
"Los_Angeles": { "offset": "-08:00", "DST-offset": "-07:00" }
},
"Asia": {
"Dubai": { "offset": "+04:00", "DST-offset": "+04:00" },
"Kolkata": { "offset": "+05:30", "DST-offset": "+05:30" }
}
}This can be achieved as follows:
<xsl:map> <xsl:for-each-group select="json-doc('tz.json') => map:pairs()" group-by="substring-before(?key, '/')"> <xsl:map-entry key="current-grouping-key()"> <xsl:map> <xsl:for-each select="current-group()"> <xsl:map-entry key="substring-after(?key, '/')" select="?value"/> </xsl:for-each> </xsl:map> </xsl:map-entry> </xsl:for-each-group> </xsl:map>
Consider a sequence of atomic values that we wish to group according to cluster. For the sake of illustration we restrict ourselves to integers. For each integer, the group it is in should include every other integer of proximate distance two or less.
<xsl:variable name="ages" as="xs:integer*" select="5, 24, 9, 5, 6, 8, 36, 38, 28">
We want to return the following four groups:
map { 1 : (5, 9, 5, 6, 8), 2 : (24), 3 : (36, 38), 4 : (28)}Solution:
<xsl:map> <xsl:for-each-group select="$ages" merge-when="function($a, $b){abs($a - $b) le 2}"> <xsl:map-entry key="position()" select="current-group()"/> </xsl:for-each-group> </xsl:map>
The next example shows how the component parts of multiple versions of a text can be collated when they refer to overlapping reference systems. Suppose we have a text, with various commentaries and glosses, and we wish to collate them by text cluster, for online presentation.
<body type="source"> <div ref="7a1">[text]</div> <div ref="7a2">[text]</div> <div ref="7a3">[text]</div> <div ref="7a4">[text]</div> <!-- . . . --> </body>
<body type="commentary"> <div ref="7a1 7a2">[commentary A]</div> <!-- . . . --> </body>
<body type="commentary"> <div ref="7a2 7a3">[commentary B]</div> <!-- . . . --> </body>
<body type="gloss"> <div ref="7a1">[gloss A]</div> <!-- . . . --> </body>
<body type="gloss"> <div ref="7a4">[gloss B]</div> <!-- . . . --> </body>
We wish to collate text portions, and display the grouped clusters in an HTML fragment:
<div class="edition"> <div class="text-cluster"> <div class="ref">7a1</div> <div class="ref">7a2</div> <div class="ref">7a3</div> <div class="source">[text]</div> <div class="commentary">[commentary A]</div> <div class="commentary">[commentary B]</div> <div class="gloss">[gloss A]</div> </div> <div class="text-cluster"> <div class="ref">7a4</div> <div class="source">[text]</div> <div class="gloss">[gloss B]</div> </div> </div>
In this solution, we bind all the texts to a variable, $versions, and we pass a template copy of the desired HTML output through a designated XSLT mode. At the appropriate place, we collate the versions by using group-by-cluster:
<xsl:template match="html:div[@class eq 'edition']" mode="collate-versions"> <xsl:copy> <xsl:copy-of select="@*"/> <xsl:for-each-group select="$versions//body/div" merge-when="function($a, $b){tokenize($a/@ref) = tokenize($b/@ref)}"> <div class="text-cluster"> <xsl:for-each select="distinct-values(current-group() ! tokenize(@ref))"> <div class="ref"> <xsl:value-of select="."/> </div> </xsl:for-each> <xsl:for-each-group select="current-group()" group-by="../@type"> <div> <xsl:attribute name="class" select="current-grouping-key()"/> <xsl:apply-templates mode="#current"/> </div> </xsl:for-each-group> </div> </xsl:for-each-group> </xsl:copy> </xsl:template>
XSLT 3.0 introduces a number of constructs that are specifically designed to enable streamed applications to be written, but which are also useful in their own right; it also includes some features that are very specialized to streaming.
Accumulators are introduced in XSLT 3.0 to enable data that is read during streamed processing of a document to be accumulated, processed or retained for later use. However, they may equally be used with non-streamed processing.
[Definition: An accumulator defines a series of values associated with the nodes of the tree. If an accumulator is applicable to a particular tree, then for each node in the tree, other than attribute and namespace nodes, there will be two values available, called the pre-descent and post-descent values. These two values are available via a pair of functions, accumulator-before and accumulator-after.]
There are two ways the values of an accumulator can be established for a given tree: they can be computed by evaluating the rules appearing in the xsl:accumulator declaration, or they can be copied from the corresponding nodes in a different tree. The second approach (copying the values) is available via the snapshot and copy-of functions, or by use of the xsl:copy-of instruction specifying copy-accumulators="yes". Accumulator values are also copied during the implicit invocation of the snapshot function performed by the xsl:merge instruction.
Note:
Accumulators can apply to trees rooted at any kind of node. But because they are most often applied to trees rooted at a document node, this section sometimes refers to the “document” to which an accumulator applies; use of this term should be taken to include all trees whether or not they are rooted at a document node.
Accumulators can apply to trees rooted at nodes (such as text nodes) that cannot have children, though this serves no useful purpose. In the case of a tree rooted at an attribute or namespace node, there is no way to obtain the value of the accumulator.
The following sections give first, the syntax rules for defining an accumulator; then an informal description of the semantics; then a more formal definition; and finally, examples. But to illustrate the concept intuitively, the following simple example shows how an accumulator can be used for numbering of nodes:
This example assumes document input in which figure elements can appear within chapter elements (which we assume are not nested), and the requirement is to render the figures with a caption that includes the figure number within its containing chapter.
When the document is processed using streaming, the xsl:number instruction is not available, so a solution using accumulators is needed.
The required accumulator can be defined and used like this:
<xsl:accumulator name="figNr" as="xs:integer" initial-value="0" streamable="yes"> <xsl:accumulator-rule match="chapter" select="0"/> <xsl:accumulator-rule match="figure" select="$value + 1"/> </xsl:accumulator> <xsl:mode streamable="yes"/> <xsl:template match="figure" expand-text="yes"> <xsl:apply-templates/> <p>Figure <{xsl:value-of select="accumulator-before('figNr')"}/></p> </xsl:template>
Consider an XHTML document in which the title of the document is represented by the content of a title element appearing as a child of the head element, which in turn appears as a child of the html element. Suppose that we want to process the document in streaming mode, and that we want to avoid outputting the content of the h1 element if it is the same as the document title.
This can be achieved by remembering the value of the title in an accumulator variable.
<xsl:accumulator name="firstTitle" as="xs:string?" initial-value="()" streamable="yes"> <xsl:accumulator-rule match="/html/head/title/text()" select="string(.)"/> </xsl:accumulator>
Subsequently, while processing an h1 element appearing later in the document, the value can be referenced:
<xsl:template match="h1"> <xsl:variable name="firstTitle" select="accumulator-before('firstTitle')"/> <xsl:variable name="thisTitle" select="string(.)"/> <xsl:if test="$thisTitle ne $firstTitle"> <div class="heading-1"><xsl:value-of select="$thisTitle"/></div> </xsl:if> </xsl:template>
Suppose that there is a requirement to output, at the end of the HTML rendition of a document, a paragraph giving the total number of words in the document.
An accumulator can be used to maintain a (crude) word count as follows:
<xsl:accumulator name="word-count" as="xs:integer" initial-value="0"> <xsl:accumulator-rule match="text()" select="$value + count(tokenize(.))"/> </xsl:accumulator>
The final value can be output at the end of the document:
<xsl:template match="/"> <xsl:apply-templates/> <p>Word count: <xsl:value-of select="accumulator-after('word-count')"/></p> </xsl:template>
Consider a document in which section elements are nested within section elements to arbitrary depth, and there is a requirement to render the document with hierarchic section numbers of the form 3.5.1.4.
The current section number can be maintained in an accumulator in the form of a sequence of integers, managed as a stack. The number of integers represents the current level of nesting, and the value of each integer represents the number of preceding sibling sections encountered at that level. For convenience the first item in the sequence represents the top of the stack.
<xsl:accumulator name="section-nr" as="xs:integer*" initial-value="0"> <xsl:accumulator-rule match="section" phase="start" select="0, head($value)+1, tail($value)"/> <xsl:accumulator-rule match="section" phase="end" select="tail($value) (:pop:)"/> </xsl:accumulator>
To illustrate this, consider the values after processing a series of start and end tags:
| events | accumulator value | required section number |
|---|---|---|
<section> | 0, 1 | 1 |
<section> | 0, 1, 1 | 1.1 |
</section> | 1, 1 | |
<section> | 0, 2, 1 | 1.2 |
</section> | 2, 1 | |
<section> | 0, 3, 1 | 1.3 |
<section> | 0, 1, 3, 1 | 1.3.1 |
</section> | 1, 3, 1 | |
<section> | 0, 2, 3, 1 | 1.3.2 |
</section> | 2, 3, 1 | |
</section> | 3, 1 | |
</section> | 1 |
The section number for a section can thus be generated as:
<xsl:template match="section"> <p> <xsl:value-of select="reverse(tail(accumulator-before('section-nr')))" separator="."/> </p> <xsl:apply-templates/> </xsl:template>
<xsl:accumulator name="histogram" as="map(xs:string, xs:integer)" initial-value="{}"> <xsl:accumulator-rule match="book"> <xsl:choose> <xsl:when test="map:contains($value, @publisher)"> <xsl:sequence select="map:put($value, string(@publisher), $value(@publisher)+1)"/> </xsl:when> <xsl:otherwise> <xsl:sequence select="map:put($value, string(@publisher), 1)"/> </xsl:otherwise> </xsl:choose> </xsl:accumulator-rule> </xsl:accumulator>
The contained sequence constructor is evaluated with the variable $value set to the current value, and with the context node as the node being visited.
Note:
In the two calls on map:put(), it is necessary to explicitly convert @publisher to an xs:string value, because this is the declared type of the keys in the result map. Relying on atomization would produce keys of type xs:untypedAtomic, which would not satisfy the declared type of the map.
The accumulated histogram might be displayed as follows:
<xsl:source-document streamable="yes" href="booklist.xml" expand-text="yes"> ..... <h1>Number of books, by publisher</h1> <table> <thead> <th>Publisher</th> <th>Number of books</th> </thead> <tbody> <xsl:variable name="histogram" select="accumulator-after('histogram')"/> <xsl:for-each select="map:keys($histogram)"> <tr> <td>{<xsl:value-of select="."}/></td> <td>{<xsl:value-of select="$histogram(.)"}/></td> </tr> </xsl:for-each> </tbody> </table> </xsl:source-document>
This section contains rules that can be used to determine properties of constructs in the stylesheet — specifically, the posture and sweep of a construct — which enable the streamability of the stylesheet to be assessed.
These properties are used to determine the streamability of:
The xsl:source-document instruction: see 18.1 The xsl:source-document Instruction
Stylesheet functions: see 19.8.5 Classifying Stylesheet Functions
The xsl:merge instruction: see 15.4 Streamable Merging
In each case, the conditions for constructs to be guaranteed-streamable are defined in terms of these properties. The result of this analysis in turn (see 19.10 Streamability Guarantees) imposes rules on how the constructs are handled by processors that implement the streaming feature. The analysis has no effect on the behavior of processors that do not implement this feature.
The analysis is relevant to constructs such as streamable template rules and the xsl:source-document instruction that process a single streamed input document. The xsl:merge instruction, which processes multiple streamed inputs, has its own rules.
The rules in this section operate on the expression tree (more properly, construct tree) that is typically output by the XSLT and XPath parser. For the most part, the rules depend only on identifying the syntactic constructs that are present.
The rules in this section generally consider each component in the stylesheet (and in the case of template rules, each template rule) in isolation. The exception is that where a component contains references to other components (such as global variables, functions, or named templates), then information from the signature of the referenced component is sometimes used. This is invariably information that cannot be changed if a component is overridden in a different package. The analysis thus requires as a pre-condition that function calls and calls on named templates have been resolved to the extent that the corresponding function/template signature is known.
The detailed way in which the construct tree is derived from the lexical form of the stylesheet is not described in this specification. There are many ways in which the tree can be optimized without affecting the result of the rules in this section: for example, a sequence constructor containing a single instruction can be replaced by that instruction, and a parenthesized expression can be replaced by its content.
[Definition: The term construct refers to the union of the following: a sequence constructor, an instruction, an attribute set, a value template, an expression, or a pattern.]
These constructs are classified into construct kinds: in particular, instructions are classified according to the name of the XSLT instruction, and expressions are classified according to the most specific production in the XPath grammar that the expression satisfies. (This means, for example, that 2+2 is classified as an AdditiveExpr, rather than say as a UnionExpr; although it also satisfies the production rule for UnionExpr, AdditiveExpr is more specific.)
[Definition: For every construct kind, there is a set of zero or more operand roles.] For example, an AdditiveExpr has two operand roles, referred to as the left-hand operand and the right-hand operand, while an IfExpr has three, referred to as the condition, the then-clause, and the else-clause. A function call with three arguments has three operand roles, called the first, second, and third arguments. The names of the operand roles for each construct kind are not formally listed, but should be clear from the context.
[Definition: In an actual instance of a construct, there will be a number of operands. Each operand is itself a construct; the construct tree can be defined as the transitive relation between constructs and their operands.] Each operand is associated with exactly one of the operand roles for the construct type. There may be operand roles where the operand is optional (for example, the separator attribute of the xsl:value-of instruction), and there may be operand roles that can be occupied by multiple operands (for example, the xsl:when/@test condition in xsl:choose, or the arguments of the concat function).
Operand roles have a number of properties used in the analysis:
The required type of the operand. This is explicit in the case of function calls (the required type is defined in the function signature of the corresponding function). In other cases it is implicit in the detailed rules for the construct in question. In practice streamability analysis makes only modest use of the required type; the main case where it is relevant is for a function or template call, where knowing that the required type is atomic enables the inference that the operand usage for a supplied node is absorption.
[Definition: The operand usage. This gives information, in the case where the operand value contains nodes, about how those nodes are used. The operand usage takes one of the values absorption, inspection, transmission, or navigation.] The meanings of these terms are explained in 19.3 Operand Roles. If the required type of the operand does not permit nodes to be supplied (for example because the required type is a function item or a map), then the operand usage is inspection, because the only run-time operation on a supplied node will be to inspect it, discover it is a node, and raise a type error.
In the particular case where the required type is atomic, and any supplied nodes are atomized, the operand usage will be absorption, because atomize is a special case of absorption.
[Definition: Whether or not the operand is higher-order. For this purpose an operand O of a construct C is higher-order if the semantics of C potentially require O to be evaluated more than once during a single evaluation of C.] More specifically, O is a higher-order operand of C if any of the following conditions is true:
The context item for evaluation of O is different from the context item for evaluation of C.
C is an instruction and O is a pattern (as with the from and count attributes of xsl:number, and the group-starting-with and group-ending-with attributes of xsl:for-each-group).
C is an XPath for, some, or every expression and O is the expression in its return or satisfies clause.
C is an inline function declaration and O is the expression in its body.
Note:
There is one known case where this definition makes an operand higher-order even though it is only evaluated once: specifically, the sequence constructor contained in the body of an xsl:copy instruction that has a select attribute. See 19.8.4.12 Streamability of xsl:copy for further details.
[Definition: For some construct kinds, one or more operand roles may be defined to form a choice operand group. This concept is used where it is known that operands are mutually exclusive (for example the then and else clauses in a conditional expression).]
[Definition: The combined posture of a choice operand group is determined by the postures of the operands in the group (the operand postures), and is the first of the following that applies:
If any of the operand postures is roaming, then the combined posture is roaming.
If all of the operand postures are grounded, then the combined posture is grounded.
If one or more of the operand postures is climbing and the remainder (if any) are grounded, then the combined posture is climbing.
If one or more of the operand postures is striding and the remainder (if any) are grounded, then the combined posture is striding.
If one or more of the operand postures is crawling and each of the remainder (if any) is either striding or grounded, then the combined posture is crawling.
Otherwise (for example, if the group includes both an operand with climbing posture and one with crawling posture), the combined posture is roaming.
]
[Definition: The type-determined usage of an operand is as follows: if the required type (ignoring occurrence indicator) is 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:
The static type of the construct. When the construct is evaluated, its value will always be an instance of this type. The value is a U-type; although type inferencing is capable of determining information about the cardinality as well as the item type, the streamability analysis makes no use of this.
The context item type: that is, the static type of the context item potentially used as input to the construct. When the construct is evaluated, the context item used to evaluate the construct (if it is used at all) will be an instance of this type.
[Definition: The posture of the expression. This captures information about the way in which the streamed input document is positioned on return from evaluating the construct. The posture takes one of the values climbing, striding, crawling, roaming, or grounded.] The meanings of these terms are explained in 19.4 Determining the Posture of a Construct.
[Definition: The context posture. This captures information about how the context item used as input to the construct is positioned relative to the streamed input. The context posture of a construct C is the posture of the expression whose value sets the focus for the evaluation of C.] Rules for determining the context posture of any construct are given in 19.5 Determining the Context Posture.
The sweep of the construct. The sweep of a construct gives information about whether and how the evaluation of the construct changes the current position in a streamed input document. The possible values are motionless, consuming, and free-ranging. These terms are explained in 19.6 The Sweep of a Construct.
The values of these properties for a top-level construct such as the body of a template rule determine whether the construct is streamable.
The values of these properties are not independent. For example, if the static type is atomic, then the posture will always be grounded; if the sweep is free-ranging, then the posture will always be roaming.
The posture and sweep of a construct, as defined above, are calculated in relation to a particular streamed input document. If there is more than one streamed input document, then a construct that is motionless with respect to one streamed input might be consuming with respect to another. In practice, though, the streamability analysis is only ever concerned with one particular streamed input at a time; constructs are analyzed in relation to the innermost containing xsl:template, xsl:source-document, xsl:accumulator, or xsl:merge-source element, and this container implicitly defines the streamed input document that is relevant. The streamed input document affecting a construct is always the document that contains the context item for evaluation of that construct.
This section defines the properties of every kind of construct that may appear in a stylesheet. It identifies the operand roles and their usage, and it gives the rules that define the posture and sweep of the construct. In cases where the general streamability rules apply, there is still an entry for the construct in order to define its operands and their usages, since this information is needed by the general rules.
The following sections describe this categorization for each kind of construct:
Sequence constructors: see 19.8.3 Classifying Sequence Constructors
Instructions: see 19.8.4 Classifying Instructions
Stylesheet functions: see 19.8.5 Classifying Stylesheet Functions
Attribute sets: see 19.8.6 Classifying Attribute Sets
Value templates: see 19.8.7 Classifying Value Templates
Expressions: see 19.8.8 Classifying Expressions
Patterns: see 19.8.10 Classifying Patterns
Calls to built-in functions: see 19.8.9 Classifying Calls to Built-In Functions
[Definition: Many constructs share the same streamability rules. These rules, referred to as the general streamability rules, are defined here.]
Examples of constructs that use these rules are: an arithmetic expression, an attribute value template, a sequence constructor, the xsl:text and xsl:value-of instructioninstructions, 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 19.1 Determining the Static Type of a Construct).
Note:
The static type is a U-type. For example, the static type of the expression (@*, *) is U{element(), attribute()}.
The sweepS and postureP of the operand (by applying the rules in this section 19.8 Classifying Constructs to that operand, recursively).
The operand usageU corresponding to the role of the operand within C (from the information in this section 19.8 Classifying Constructs).
Compute the adjusted sweep S′ of the operand by taking the first of the following that applies:
If S is free-ranging or P is roaming, then S′ is free-ranging. (In this case the posture and sweep of C are roaming and free-ranging, regardless of any other operands.)
If P is grounded, then S′ is S.
Otherwise (P is not grounded, which implies that the operand is capable of returning streamed nodes), compute S′ as follows:
Compute the adjusted usage U′ as follows:
If U is absorption and the intersection of T with U{element(), document-node()} is U{} (that is, if T is a type that does not allow nodes with children), then U′ is inspection.
Note:
This is because the entire subtree of nodes such as text nodes is available without reading further data from the input stream.
Otherwise, U′ is U.
Compute the adjusted 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.
This section describes how instructions are classified with respect to their streamability. The criteria are given first for literal result elements and extension instructions, then for each XSLT instruction, listed alphabetically.
xsl:textThe posture and sweep of xsl:textxsl:value-of follow the general streamability rules. ThereThe operand roles and their usages are no operands.as follows:
Note:
The instruction is therefore grounded and motionless.
The select expression (usage absorption)
The separator attribute value template (usage absorption)
The contained sequence constructor (usage absorption).