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, SG for XSLT Streaming version 4.0.
An optional feature of the XSLT language is support for streamed transformations. The XSLT 4.0 specification has been modularized so that streaming is now described in a separate specification document. This has been done in order to make the specifications more manageable, both for editors and readers: it does not alter the status of streaming as an optional feature, available in some processors and not others.
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).
This section describes the overall structure of a stylesheet as a collection of XML documents.
Changes in 4.0 (next | previous)
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. [Issue 90 PR 599 12 September 2023]
The outermost element of a simplified stylesheet need no longer be a literal result element, it can now be any instruction (including xsl:result-document). This allows a simplified stylesheet to produce JSON output as well as XML or HTML. [Issue 2322 PR 2323 30 November 2025]
A simplified syntax is allowed for a stylesheet module that defines only a single template rule. A simplified stylesheet module consist of a single instruction or literal result element together with its contents. Such a stylesheet module is equivalent to a standard stylesheet module whose xsl:stylesheet element contains a template rule containing the instruction or literal result element; the template rule has a match pattern of match=".", which matches any item.
The following example shows a stylesheet that simply evaluates one XPath expression:
<out>{count(//*)}</out>The output of the stylesheet will be an XML document such as <out>17</out> showing the number of elements found in the supplied source document.
This simplified stylesheet is defined to be equivalent to the following expanded stylesheet:
<xsl:stylesheet xmlns="http://www.w3.org/1999/XSL/Transform"
version="4.0" expand-text="yes">
<xsl:template match=".">
<out>{count(//*)}</out>
</xsl:template>
</xsl:stylesheet>Because the stylesheet contains no elements or attributes in the XSLT namespace, it does not need to contain any namespace declarations.
A simplified stylesheet can contain XSLT instructions, in which case the XSLT namespace needs to be declared. This is illustrated in the next example.
This stylesheet outputs an HTML document containing a table that summarizes the value of transactions according to their rate of tax:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xsl:version="4.0">
<head>
<title>Expenditure by Tax Rate</title>
</head>
<body>
<table>
<thead>
<tr>
<th>Gross Amount</th>
<th>Tax Rate</th>
</tr>
</thead>
<tbody>
<xsl:for-each-group select="//transaction" group-by="vat-rate">
<tr>
<td>{sum(current-group()/value)}</td>
<td>{current-grouping-key()}</td>
</tr>
</xsl:for-each-group>
</tbody>
</table>
</body>
</html>
This example expects as input a parsed JSON document containing an array of records. It outputs a serialized JSON document containing a selection of fields from these records.
<xsl:result-document method="json" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:array>
<xsl:for-each select="?*">
<xsl:record first="?firstName"
last="?surname"
phone="?mobile"/>
</xsl:for-each>
</xsl:array>
</xsl:result-document>More formally, a simplified stylesheet module is equivalent to the standard stylesheet module that would be generated by applying the following transformation to the simplified stylesheet module, invoking the transformation by calling the named templateexpand, with the outermost element as the context node:
<xsl:stylesheet version="4.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template name="expand">
<xsl:element name="xsl:stylesheet">
<xsl:variable name="version"
select="(if (self::xsl:*) then @version else @xsl:version)
otherwise '4.0'"/>
<xsl:attribute name="version" select="$version"/>
<xsl:attribute name="expand-text"
select="not(number($version) le 3.0)"/>
<xsl:element name="xsl:template">
<xsl:attribute name="match" select="'.'"/>
<xsl:copy-of select="."/>
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>The allowed content of an instruction or literal result element when used as a simplified stylesheet is the same as when it occurs within a sequence constructor. Thus, a simplified stylesheet cannot contain declarations. In particular, simplified stylesheets therefore cannot use template rules, global variables, stylesheet parameters, stylesheet functions, keys, attribute-sets, or output definitions. Furthermore, they cannot contain xsl:include, xsl:import, or xsl:use-package declarations.
The only useful way to initiate the transformation is to supply an item as the initial match selection, to be matched by the implicit match="." template rule using the unnamed mode.
Note:
There are several significant changes to simplified stylesheets in XSLT 4.0.
It is no longer required to include an xsl:version attribute; this in turn means it is often no longer necessary to declare the xsl namespace. The xsl:version attribute defaults to the version of the XSLT processor, that is, "4.0" for an XSLT 4.0 processor.
If the xsl:version attribute is omitted, or is set to "4.0" or a larger value, then the expand-text attribute defaults to true, meaning that text value templates are recognized.
The outermost element of a simplified stylesheet can be any instruction (for example, xsl:array, xsl:map, or xsl:result-document), allowing the stylesheet to deliver arrays, maps, or serialized JSON.
The match pattern of the implicit template rule uses match="." rather than match="/", allowing the initial match selection to be any item, not only a document node.
There may be edge cases where this causes a backwards incompatibility. For example, if a transformation using a simplified stylesheet is invoked supplying an element node (rather than a document node) as the initial match selection, then under 4.0 this will match the implicitly-defined template rule (match="." matches an element node), whereas in 3.0 it would have been processed using the built-in template rules for the unnamed mode. A similar situation arises if a simplified stylesheet module is imported into a larger stylesheet package, and the implicitly-defined template rule is invoked using xsl:next-match or xsl:apply-imports.
Note:
It is technically valid for the outermost element to be xsl:variable or xsl:param, because these are defined as instructions; however, this achieves no useful purpose because the result of these instructions is an empty sequence.
This section lists all known incompatibilities with XSLT 3.0, that is, situations where a stylesheet that is error-free according to the XSLT 3.0 specification and where all elements have an effective version of 3.0 or less, will produce different results depending on whether it is run under an XSLT 3.0 processor or an XSLT 4.0 processor.
The rules for comparing values in xsl:for-each-group now reference the rules for distinct-values, which have themselves changed to be compatible with fn:atomic-equal. This change eliminates the intransitivity in the previous specification, which meant that in edge cases involving rounding of numeric values of different types, two items in different groups could compare equal. Any change in behavior is confined to this edge case.
The rules for matching nodes against patterns using the intersect and except operators have changed to deliver a more intuitive result.
The rules for comparing values in keys have changed, to align with the rules for maps. The changes affect edge cases involving rounding of numeric values of different types, and the comparison of date/time values with and without timezones.
In previous versions, a template rule whose match pattern was a union pattern and that had no explicity priority was treated as equivalent to a set of template rules, one for each alternative in the union, each potentially with different default priority. This rule has not been carried forward into XSLT 4.0: instead, the priority of the rule is taken as being the highest priority of any of the alternatives.
In XSLT 4.0, an xsl:apply-imports or xsl:next-match instruction automatically passes on the values of any non-tunnel parameters that were present in its own invocation. This means that the template rule invoked by xsl:apply-imports or xsl:next-match, if it declares a default value for such a parameter, will take the implicitly-supplied value in preference to the default value.
This change in the specification applies only if the effective version of the xsl:apply-imports or xsl:next-match is 4.0 or greater. This means that 3.0 behavior can be retained by adding the attribute version="3.0" to the instruction, or to some ancestor element (for example, the xsl:stylesheet or xsl:transform element).
A module in XSLT 4.0 defines a template rule whose implicit match pattern is match="." (matching any item), whereas in XSLT 3.0 the implicit match pattern was match="/" (matching document nodes only). This change is made to allow such stylesheets to be used to process JSON input, but it also has the effect of changing the behavior of the stylesheet if it is applied to other items, such as element or text nodes.
This specification also corrects a number of errors and omissions in XSLT 3.0, in a way that might create incompatibilities for some processors, depending on how they interpreted the XSLT 3.0 specification:
XSLT 3.0 (and earlier releases) did not fully define the evaluation context for the default values of template parameters. For example, if the default value of a parameter of a template rule invoked xsl:next-match, it was not specified whether the current template rule should be the calling template or the called template. This omission has been corrected.
Where different packages import different schemas, the specification is now more prescriptive about which schema is used for validation. The rules may differ from the conventions adopted by implementations of XSLT 3.0.
XSLT 3.0 failed to specify a default value for the serialization parameter indent where the serialization method is json or adaptive. XSLT 4.0 specifies a default value of no.
See also [XPath 4.0], [Functions and Operators 4.0], and [Serialization 4.0] for incompatibilities in other related specifications that may affect XSLT stylesheets.