View Old View New View Both View Only Previous Next

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

W3C

XSL Transformations (XSLT) Version 4.0

W3C Editor's Draft 23 February 2026

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

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


Abstract

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

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

XSLT 4.0 is designed to be used in conjunction with XPath 4.0, which is defined in [XPath 4.0]. XSLT shares the same data model as XPath 4.0, which is defined in [XDM 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.

Status of this Document

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

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

Dedication

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


3 Stylesheet Structure

This section describes the overall structure of a stylesheet as a collection of XML documents.

3.5 Packages

[Definition: An explicit package is represented by an xsl:package element, which will generally be the outermost element of an XML document. When the xsl:package element is not used explicitly, the entire stylesheet comprises a single implicit package.] (This specification does not preclude the xsl:package being embedded in another XML document, but it will never have any other XSLT element as an ancestor).

<xsl:package
  id? = id
  name? = uri
  package-version? = string〔'1'〕
  version = decimal
  input-type-annotations? = "preserve" | "strip" | "unspecified"〔'unspecified'〕
  declared-modes? = boolean〔'yes'〕
  default-mode? = eqname | "#unnamed"〔'#unnamed'〕
  default-validation? = "preserve" | "strip"〔'strip'〕
  default-collation? = uris
  extension-element-prefixes? = prefixes
  exclude-result-prefixes? = prefixes
  expand-text? = boolean〔'no'〕
  fixed-namespaces? = string
  schema-role? = ncname
  use-when? = expression〔true()〕
  xpath-default-namespace? = uri >
  <!-- Content: ((xsl:expose | declarations)*) -->
</xsl:package>

[Definition: The content of the xsl:package element is referred to as the package manifest].

The version attribute indicates the version of the XSLT language specification to which the package manifest conforms. The value should normally be 4.0. If the value is numerically less than 4.0, the content of the xsl:package element is processed using the rules for backwards compatible behavior (see 3.9 Backwards Compatible Processing). If the value is numerically greater than 4.0, it is processed using the rules for forwards compatible behavior (see 3.10 Forwards Compatible Processing).

A package typically has a name, given in its name attribute, which must be an absolute URI. Unnamed packages are allowed, but they can only be used as the “top level” of an application; they cannot be the target of an xsl:use-package declaration in another package.

A package may have a version identifier, given in its package-version attribute. This is used to distinguish different versions of a package. The value of the version attribute, after trimming leading and trailing whitespace, must conform to the syntax given in 3.5.1 Versions of a Package. If no version number is specified for a package, version 1 is assumed.

The attributes default-collation, default-mode, default-validation, exclude-result-prefixes, expand-text, extension-element-prefixes, use-when, version, and xpath-default-namespace are standard attributes that can appear on any XSLT element, and potentially affect all descendant elements. Their meaning is described in 3.4 Standard Attributes.

The package manifest contains the following elements, arbitrarily ordered:

  1. Zero or more xsl:expose declarations that define the interface offered by this package to the outside world. An xsl:expose declaration may appear only as a child of xsl:package.

  2. Zero or more additional declarations. These are the same as the declarations permitted as children of xsl:stylesheet or xsl:transform.

    Some declarations of particular relevance to packages include:

    1. The xsl:use-package declaration, which declares the names and versions of the packages on which this package depends.

    2. The optional xsl:global-context-item element; if present this element defines constraints on the existence and type of the global context item.

    3. Zero or more xsl:include and xsl:import declarations, which define additional stylesheet modules to be incorporated into this package.

    4. Zero or more ordinary declarations, that is, elements that are permitted as children of xsl:stylesheet or xsl:transform. One possible coding style is to include in the package manifest just a single xsl:import or xsl:include declaration as a reference to the effective top-level stylesheet module; this approach is particularly suitable when writing code that is required to run under releases of XSLT earlier than 3.0. Another approach is to include the substance of the top-level stylesheet module inline within the package manifest.

Example: An example package

The following example shows a package that offers a number of functions for manipulating complex numbers. A complex number is represented as a map with two entries, the keys being 0 for the real part, and 1 for the imaginary part.

<xsl:package
  name="http://example.org/complex-arithmetic.xsl"
  package-version="1.0"
  version="3.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:f="http://example.org/complex-arithmetic.xsl">
  
  <xsl:function name="f:complex-number" 
                as="map(xs:integer, xs:double)" visibility="public">
    <xsl:param name="real" as="xs:double"/>
    <xsl:param name="imaginary" as="xs:double"/>
    <xsl:sequence select="{ 0: $real, 1: $imaginary }"/>
  </xsl:function>
  
  <xsl:function name="f:real" 
                as="xs:double" visibility="public">
    <xsl:param name="complex" as="map(xs:integer, xs:double)"/>
    <xsl:sequence select="$complex(0)"/>
  </xsl:function>
  
  <xsl:function name="f:imag" 
                as="xs:double" visibility="public">
    <xsl:param name="complex" as="map(xs:integer, xs:double)"/>
    <xsl:sequence select="$complex(1)"/>
  </xsl:function>
  
  <xsl:function name="f:add" 
                as="map(xs:integer, xs:double)" visibility="public">
    <xsl:param name="x" as="map(xs:integer, xs:double)"/>
    <xsl:param name="y" as="map(xs:integer, xs:double)"/>
    <xsl:sequence select="
         f:complex-number(
           f:real($x) + f:real($y), 
           f:imag($x) + f:imag($y))"/>
  </xsl:function>
  
  <xsl:function name="f:multiply" 
                as="map(xs:integer, xs:double)" visibility="public">
    <xsl:param name="x" as="map(xs:integer, xs:double)"/>
    <xsl:param name="y" as="map(xs:integer, xs:double)"/>
    <xsl:sequence select="
         f:complex-number(
           f:real($x)*f:real($y) - f:imag($x)*f:imag($y),
           f:real($x)*f:imag($y) + f:imag($x)*f:real($y))"/>
  </xsl:function>
  
  <!-- etc. -->
  
</xsl:package>

A more complex package might include private or abstract functions as well as public functions; it might expose components other than functions (for example, templates or global variables), and it might contain xsl:use-package elements to allow it to call on the services of other packages.

Note:

In this example, the way in which complex numbers are represented is exposed to users of the package. It would be possible to hide the representation by declaring the types on public functions simply as item(); but this would be at the cost of type safety.

A package that does not itself expose any components may be written using a simplified syntax: the xsl:package element is omitted, and the xsl:stylesheet or xsl:transform element is now the outermost element of the stylesheet module. For compatibility reasons, all the named templates and modes declared in the package are made public. More formally, the principal stylesheet module of the top-level package may be expressed as an xsl:stylesheet or xsl:transform element, which is equivalent to the package represented by the output of the following transformation, preserving the base URI of the source:

<xsl:transform version="3.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:t="http://www.w3.org/1999/XSL/TransformAlias">
 
    <xsl:namespace-alias stylesheet-prefix="t" result-prefix="xsl"/>
    
    <xsl:template match="xsl:stylesheet|xsl:transform">
      <t:package declared-modes="no">
        <xsl:copy-of select="@*"/>
        <t:expose component="mode" names="*" visibility="public"/>
        <t:expose component="template" names="*" visibility="public"/>
        <xsl:copy-of select="node()"/>
      </t:package>
    </xsl:template>
 </xsl:transform>

The effect of the input-type-annotations attribute is defined in 4.3.1 Stripping Type Annotations from a Source Tree.

A more extensive example of a package, illustrating how components in a package can be overridden in a client package, is given in 3.5.7 Worked Example of a Library Package.

3.5.1 Versions of a Package

If a package has a version number, the version number must conform to the grammar:

        PackageVersion   ::= NumericPart ( "-" NamePart )?
        NumericPart      ::= IntegerLiteral ( "." IntegerLiteral )*
        NamePart         ::= NCName

Here IntegerLiteralXP and NCName are as defined in the XPath 4.0 grammar productions of the same name (including rules on limits). Leading and trailing whitespace is ignored; no other whitespace is allowed.

Examples of valid version numbers are 2.0.5 or 3.10-alpha.

[Definition: The integer literals and the optional NamePart within the version number are referred to as the portions of the version number.]

Note:

This means that 1-alpha-2 is a valid version number, with two portions: 1 and alpha-2. The second hyphen is part of the NCName, it does not act as a portion separator.

Versions are ordered. When comparing two versions:

  1. Trailing zero portions (that is, any zero-valued integer that is not followed by another integer) are discarded.

  2. Comparison proceeds by comparing portions pairwise from the left.

  3. If both versions have the same number of portions and all portions compare equal (under the rules of the XPath eq operator using the Unicode codepoint collation), then the versions compare equal.

  4. If the number of portions in the two versions V1 and V2 is N1 and N2, with N1<N2, and if all portions in positions 1 to N compare equal, then V1 is less than V2 if the portion of V2 in position N1 is an integer, and is greater than V2 if this portion is an NCName. For example, 1.2 is less than 1.2.5, while 2.0 is greater than 2.0-rc1.

  5. Portions are compared as follows:

    1. If both portions are integers, they are compared using the rules of XPath value comparisons.

    2. If both portions are NCNames, they are compared using the rules of XPath value comparisons, using the Unicode Codepoint Collation.

    3. If one portion is an integer and the other is an NCName, the NCName comes first.

For example, the following shows a possible ordered sequence of version numbers:

0-rc1 < 0-rc2 < 0 < 1 = 1.0 < 1.0.2 
   < 1.0.3-rc1 < 1.0.3 < 1.0.3.2 < 1.0.10

Note:

The version number format defined here is designed to be general enough to accommodate a variety of conventions in common use, and to allow useful semantics for matching of versions and ranges of versions, without being over-prescriptive. It is influenced by [SemVer], but is not as prescriptive, and it imposes no assumptions about backwards compatibility of packages between successive versions.

Implementations may impose limits on the values used in a version number (or a version range: see below). Such limits are implementation-defined. As a minimum, a processor must accept version numbers including:

  • A numeric part containing four integers;

  • Each integer being in the range 0 to 999999;

  • An NCName of up to 100 characters

Dependencies between packages may specify a version range (see 3.5.2 Dependencies between Packages). A version range represents a set of accepted versions. The syntax of a version range is shown below. Whitespace is permitted only where indicated, using the terminal symbol S.

        PackageVersionRange    ::=  AnyVersion | VersionRanges
        AnyVersion             ::=  "*"
        VersionRanges          ::=  VersionRange (S? "," S? VersionRange)*
        VersionRange           ::=  PackageVersion | VersionPrefix | 
                                      VersionFrom | VersionTo | VersionFromTo
        VersionPrefix          ::=  PackageVersion ".*"
        VersionFrom            ::=  PackageVersion "+"
        VersionTo              ::=  "to" S (PackageVersion | VersionPrefix)
        VersionFromTo          ::=  PackageVersion S "to" S (PackageVersion | VersionPrefix)
        PackageVersionRange    ::=  AnyVersion | VersionRanges
        AnyVersion             ::=  "*"
        VersionRanges          ::=  VersionRange (S? "," S? VersionRange)*
        VersionRange           ::=  PackageVersion | VersionPrefix | 
                                      VersionFrom | VersionTo | VersionFromTo
        VersionPrefix          ::=  PackageVersion ".*"
        VersionFrom            ::=  PackageVersion "+"
        VersionTo              ::=  "to" S (PackageVersion | VersionPrefix)
        VersionFromTo          ::=  PackageVersion S 
                                      "to" S (PackageVersion | VersionPrefix)

The meanings of the various forms of version range are defined below:

  • The range AnyVersion matches any version.

  • The range VersionRanges matches a version if any constituent VersionRange matches that version.

    For example, 9.5.0.8, 9.6.1.2 matches those specific versions only, while 9.5.0.8, 9.6+ matches either version 9.5.0.8 or any version from 9.6 onwards.

  • A range that is a PackageVersion matches that version only.

  • The range VersionPrefix matches any version whose leading portions are the same as the portions in the PackageVersion part of the VersionPrefix.

    For example, 1.3.* matches 1.31.3.51.3.10.2,  and 1.3-beta (but not 1 or 1.4).

    Note:

    The .* indicates that additional portions may follow; it does not indicate a substring match on the final portion. So 1.3.* does not match 1.35, and 3.3-beta.* does not match 3.3-beta12. Also, 3.3-beta.* does not match 3.3-beta.5: this is because the last dot is not a portion separator, but is part of the final NCName. In fact, using .* after a version number that includes an NCName portion is pointless, because an NCName portion can never be followed by further portions.

  • The range VersionFrom matches any version that is greater than or equal to the version supplied.

    For example 1.3+ matches 1.31.3.21.4,  and 2.1 (but not 1.3-beta or 1.2). And 1.3-beta+ matches 1.3-beta1.3-gamma1.3.01.4, and 8.0, but not 1.3-alpha or 1.2.

  • The range VersionTo matches any version that is less than or equal to some version that matches the supplied PackageVersion or VersionPrefix.

    For example, to 4.0 matches 1.52.33.84.0,  and 4.0-beta (but not 4.0.1), while to 3.3.* matches 1.5 or 2.0.6 or 3.3.4621, but not 3.4.0 or 3.4.0-beta.

  • The range VersionFromTo matches any version that is greater than or equal to the starting PackageVersion, and less than or equal to some version that matches the ending PackageVersion or VersionPrefix.

    For example, 1 to 5 matches 1.12.13.1,  or 5.0 (but not 5.1), while 1 to 5.* matches all of these, plus versions such as 5.7.2 (but not 6.0 or 6.0-beta). Similarly, 1.0-beta to 1.0 matches 1.0-beta, 1.0-beta.2, 1.0-gamma, and 1.0, but not 1.0-alpha or 1.0.1.