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.
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 3.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. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at https://www.w3.org/TR/.
This document has no official standing. It is produced by the editor as a proposal for community review. Insofar as it copies large amounts of text from the W3C XSLT 3.0 Recommendation, W3C copyright and similar provisions apply.
The publications of this community group are dedicated to our co-chair, Michael Sperberg-McQueen (1954–2024).
[Definition: The two elements xsl:variable and xsl:param are referred to as variable-binding elements.]
[Definition: The xsl:variable element declares a variable, which may be a global variable or a local variable.]
[Definition: The xsl:param element declares a parameter, which may be a stylesheet parameter, a template parameter, a function parameter, or an xsl:iterate parameter. A parameter is a variable with the additional property that its value can be set by the caller.]
[Definition: A variable is a binding between a name and a value. The value of a variable is any sequence (of nodes, atomic items, and/or function items), as defined in [XDM 3.0].]
A variable-binding with no as or select attribute no longer attempts to create an implicit document node if the sequence constructor contains an xsl:map, xsl:array, or xsl:select child instruction. [Issue 2009 PR 2015 20 May 2025]
A variable-binding element may specify the supplied value of a variable or the default value of a parameter in four different ways.
If the variable-binding element has a select attribute, then the value of the attribute must be an expression and the supplied value of the variable is the value that results from evaluating the expression. In this case, the content of the variable-binding element must be empty.
If the variable-binding element has empty content and has neither a select attribute nor an as attribute, then the supplied value of the variable is a zero-length string. Thus
<xsl:variable name="x"/>
is equivalent to
<xsl:variable name="x" select="''"/>
If a variable-binding element satisfies all the following conditions:
The element has no select attribute
The element has no as attribute
The element has non-empty content (that is, the variable-binding element has one or more child nodes)
There is no xsl:map, xsl:array, or xsl:select element among the element's children
then the content of the variable-binding element specifies the supplied value. The content of the variable-binding element is a sequence constructor; a new document is constructed with a document node having as its children the sequence of nodes that results from evaluating the sequence constructor and then applying the rules given in 5.8.1 Constructing Complex Content. The value of the variable is then a singleton sequence containing this document node. For further information, see 9.4 Creating Implicit Document Nodes.
Otherwise, the supplied value is the sequence that results from evaluating the (possibly empty) sequence constructor contained within the variable-binding element (see 5.8 Sequence Constructors).
These combinations are summarized in the table below.
| select attribute | as attribute | content | Effect |
|---|---|---|---|
| present | absent | empty | Value is obtained by evaluating the select attribute |
| present | present | empty | Value is obtained by evaluating the select attribute, coerced to the type required by the as attribute |
| present | absent | present | Static error |
| present | present | present | Static error |
| absent | absent | empty | Value is a zero-length string |
| absent | present | empty | Value is an empty sequence, provided the as attribute permits an empty sequence |
| absent | absent | includes xsl:map, xsl:array, or xsl:select | Value is obtained by evaluating the sequence constructor |
| absent | absent | present and does not include xsl:map, xsl:array, or xsl:select | Value is a document node whose content is obtained by evaluating the sequence constructor |
| absent | present | present | Value is obtained by evaluating the sequence constructor, coerced to the type required by the as attribute |
[ERR XTSE0620] It is a static error if a variable-binding element has a select attribute and has non-empty content.
The value of the following variable is the sequence of integers (1, 2, 3):
<xsl:variable name="i" as="xs:integer*" select="1 to 3"/>
The value of the following variable is an integer, assuming that the attribute @size exists, and is annotated either as an integer, or as xs:untypedAtomic:
<xsl:variable name="i" as="xs:integer" select="@size"/>
The value of the following variable is a zero-length string:
<xsl:variable name="z"/>
The value of the following variable is a document node containing an empty element as a child:
<xsl:variable name="doc"><c/></xsl:variable>
The value of the following variable is a sequence of integers (2, 4, 6):
<xsl:variable name="seq" as="xs:integer*"> <xsl:for-each select="1 to 3"> <xsl:sequence select=".*2"/> </xsl:for-each> </xsl:variable>
The value of the following variable is a sequence of parentless attribute nodes:
<xsl:variable name="attset" as="attribute()+"> <xsl:attribute name="x">2</xsl:attribute> <xsl:attribute name="y">3</xsl:attribute> <xsl:attribute name="z">4</xsl:attribute> </xsl:variable>
The value of the following variable is an empty sequence:
<xsl:variable name="empty" as="empty-sequence()"/>
The actual value of the variable depends on the supplied value, as described above, and the required type, which is determined by the value of the as attribute.
When a variable is used to select nodes by position, be careful not to do:
<xsl:variable name="n">2</xsl:variable> ... <xsl:value-of select="td[$n]"/>
This will output the values of all the td elements, space-separated (or with XSLT 1.0 behavior, the value of the first td element), because the variable n will be bound to a node, not a number. Instead, do one of the following:
<xsl:variable name="n" select="2"/> ... <xsl:value-of select="td[$n]"/>
or
<xsl:variable name="n">2</xsl:variable> ... <xsl:value-of select="td[position()=$n]"/>
or
<xsl:variable name="n" as="xs:integer">2</xsl:variable> ... <xsl:value-of select="td[$n]"/>
Use the arrows to browse significant changes since the 3.0 version of this specification.
Sections with significant changes are marked Δ in the table of contents.
Named item types can be declared using the new xsl:item-type element. This is designed to avoid repeating lengthy type definitions (for example function types) every time they are used. [This feature was present in the editor's draft presented to the WG when it started work.]
The xsl:for-each and xsl:apply-templates instructions acquire an attribute separator that can be used to insert content between adjacent items. [This change was in the editor's draft adopted as a baseline when the WG commenced work.]
PR 751 1386
The result type of a mode can be declared using an as attribute. The result type of all template rules in this mode must be consistent with this, as must the values returned by any built-in template rules for the mode.
The xsl:for-each and xsl:apply-templates instructions acquire an attribute separator that can be used to insert content between adjacent items. [This change was in the editor's draft adopted as a baseline when the WG commenced work.]
Numeric values of type xs:decimal are compared as decimals, without first converting to xs:double.
Functions that accept a lexical QName as an argument, such as key, function-available, element-available, type-available, system-property, accumulator-before, and accumulator-after, now have the option of supplying an xs:QName value instead. [This change was in the editor's draft accepted by the WG as its baseline when it started work.]
Functions that accept a lexical QName as an argument, such as key, function-available, element-available, type-available, system-property, accumulator-before, and accumulator-after, now have the option of supplying an xs:QName value instead. [This change was in the editor's draft accepted by the WG as its baseline when it started work.]
It is possible to invoke a named template using an extension instruction, specifically, an element whose name matches the name of the named template.
See 10.1.3 Invoking Named Templates using Extension Instructions
A new attribute xsl:map/@duplicates is available, allowing control over how duplicate keys are handled by the xsl:map instruction.
The semantics of patterns using the intersect and except operators have been changed to reflect the intuitive meaning: for example a node now matches A except B if it matches A and does not match B.
A new attribute xsl:for-each-group/@split-when is available to give applications more complete control over how a sequence is partitioned
See 14 Grouping
Duplicate xsl:include declarations within a stylesheet level are now ignored, preventing spurious errors caused by the presence of duplicate named components.
Named record types are introduced.
The contents of a character map declared using xsl:character-map are now available dynamically via a new character-map function.
New variables err:stack-trace, err:additional, and err:map are available within an xsl:catch clause.
See 8.4 Try/Catch
The input to the serializer can be defined using the select attribute of xsl:result-document as an alternative to using a sequence constructor.
It is no longer an intrinsic error for a global variable to refer to itself; this is now permitted, for example in cases where the value of the global variable is a recursive inline function. Cases where self-reference would not make sense are covered by the existing rules on circularities: see 9.11 Circular Definitions.
The default value for the indent parameter is now defined to be no for all output methods other than html and xhtml.
The xsl:map instruction allows a select attribute as an alternative to the contained sequence constructor.
The xsl:map-entry instruction, in common with other instructions, now raises error XTSE3185 (rather than XTSE3280) if both a select attribute and a sequence constructor are present.
Composite sort keys are allowed in xsl:sort.
The xsl:mode declaration acquires an attribute copy-namespaces which determines whether or not the built-in template rule copies unused namespace bindings.
The default priority for a template rule using a union pattern has changed. This change may cause incompatible behavior.
The xsl:apply-imports and xsl:next-match instructions automatically pass supplied parameters to the overridden template rule.
The xsl:select instruction is new in 4.0.
A variable-binding with no as or select attribute no longer attempts to create an implicit document node if the sequence constructor contains an xsl:map, xsl:array, or xsl:select child instruction.
PR 159
Parameters on functions declared using xsl:function can now be defined as optional, with a default value supplied.
PR 237
The xsl:if instruction now allows then and else attributes.
See 8.1 Conditional Processing with xsl:if
In xsl:choose, the xsl:when and xsl:otherwise elements can take a select attribute in place of a sequence constructor.
See 8.2 Conditional Processing with xsl:choose
A new xsl:switch instruction is introduced.
PR 326
The higher-order-function feature no longer exists; higher-order functions are now a core part of XSLT, no longer an optional extra.
See 27 Conformance
PR 353
A new attribute, main-module, is added to the xsl:stylesheet element. The attribute is provided for the benefit of development tools such as syntax-directed editors to provide information about all the components (variables, functions, etc) visible within a stylesheet module.
A new element xsl:note is available for documentation and similar purposes: it can appear anywhere in the stylesheet and is ignored by the XSLT processor.
PR 401
Patterns (especially those used in template rules) can now be defined by reference to item types, so any item type can be used as a match pattern. For example match="record(longitude, latitude, *)" matches any map that includes the key values "longitude" and "latitude".
PR 406
The new instruction xsl:array is introduced to allow construction of arrays.
PR 470
The xsl:stylesheet, xsl:transform, or xsl:package element may have a fixed-namespaces attribute making it easier to have the same namespace declarations in force throughout a stylesheet.
PR 489
The xsl:matching-substring and xsl:non-matching-substring elements within xsl:analyze-string may now take a select attribute in place of a contained sequence constructor.
PR 534
A new serialization parameter escape-solidus is provided to control whether the character / is escaped as \/ by the JSON serialization method.
PR 542
A mode (called an enclosing mode) can be defined in which all the relevant template rules are children of the xsl:mode element. This is intended to allow a stylesheet design in which it is easier to determine which rules might apply to a given xsl:apply-templates call.
PR 599
Simplified stylesheets no longer require an xsl:version attribute (which means they might not need a declaration of the XSLT namespace). Unless otherwise specified, a 4.0 simplified stylesheet defaults expand-text to true.
PR 635
The rules concerning the compatibility of schemas imported by different packages have been clarified. It is now explicitly stated that instructions that trigger validation must use the imported schema of the package in which validation is invoked. This differs from the current practice of some XSLT 3.0 processors, which may use (for example) a schema formed from the union of the imported schemas in all packages.
See 3.15 Importing Schema Components
See 25.4 Validation
PR 717
Capturing accumulators have been added; when streaming with a capturing accumulator, the accumulator-after has full access to a snapshot of the matched element node.
PR 718
To allow recursive-descent transformation on a tree of maps and arrays, a new set of built-in templates rules shallow-copy-all is introduced.
PR 751
The xsl:mode declaration acquires an attribute as="sequence-type" which declares the return type of all template rules in that mode.
PR 1181
The [xsl:]xpath-default-namespace attribute can be set to the value ##any, which causes unprefixed element names to match in any namespace or none.
See 5.1.2 Unprefixed Lexical QNames in Expressions and Patterns
PR 1250
The strings used in the formatted number to represent a decimal separator, grouping separator, exponent separator, percent sign, per mille sign, or minus sign, are no longer constrained to be single characters.
PR 1254
The rules concerning the interpretation of xsi:schemaLocation and xsi:noNamespaceSchemaLocation attributes have been tightened up.
See 25.4 Validation
See 25.4 Validation
PR 1306
An as attribute is available on the xsl:sequence instruction.
PR 1361
The term atomic value has been replaced by atomic item.
See 2.1 Terminology
PR 1378
A function call at the outermost level can now be named using any valid EQName (for example fn:doc) provided it binds to one of the permitted functions fn:doc, fn:id, fn:element-with-id, fn:key, or fn:root. If two functions are called, for example doc('a.xml')/id('abc'), it is no longer necessary to put the second call in parentheses.
PR 1442
Default priorities are added for new forms of ElementTest and AttributeTest, for example element(p:*) and element(a|b).
PR 1622
The rules for equality comparison have changed to bring keys into line with maps.
See 20.2.2 fn:key
New in 4.0.
PR 1689
Composite merge keys are now allowed.
See 15 Merging
PR 1703
Ordered maps are introduced.
PR 1819
Different parts of a stylesheet may now use different imported schemas.
See 2.10 Stylesheets and XML Schemas
The standard attribute [xsl:]schema-role is introduced, to allow different parts of a stylesheet to use different schemas.
Different parts of a stylesheet may now use different imported schemas.
See 3.15 Importing Schema Components
A stylesheet can import multiple schemas with different schema role names.
PR 1856
The rules have been adjusted to allow for new capabilities in regular expressions, such as zero-width assertions.
PR 1858
The xsl:record instruction is introduced to make construction of record maps simpler.
Attribute xsl:record/@xsl:duplicates is added to control duplicate keys handling in the xsl:record instruction.
PR 2006
A new function fn:apply-templates is introduced.
PR 2015
A variable-binding with no as or select attribute no longer attempts to create an implicit document node if the sequence constructor contains an xsl:map, xsl:array, or xsl:select child instruction.
PR 2030
In order to reduce duplication between the XSLT and XQuery specifications, description of the validation process has been moved to the Functions and Operators specification.
See 25.4 Validation