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, 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.

Status of this Document

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.

Dedication

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


22 Arrays

Arrays are defined in the XDM Data Model: see [XDM 4.0] section 8.3 Array Items.

22.1 Array Construction

Changes in 4.0  

  1. The new instruction xsl:array is introduced to allow construction of arrays.   [Issues 113 2007 PR 406 30 March 2023]

The instruction xsl:array constructs and returns a new array.

<!-- Category: instruction -->
<xsl:array
  for-each? = expression
  select? = expression >
  <!-- Content: sequence-constructor -->
</xsl:array>

<!-- Category: instruction -->
<xsl:array-member
  select? = expression >
  <!-- Content: sequence-constructor -->
</xsl:array-member>

There are three typical ways an array might be constructed.

  1. An array whose members are all single items can be constructed using an instruction such as:

    <xsl:array select="'Mon', 'Tues', 'Weds', 'Thurs', 'Fri'"/>

    This constructs an array of five strings: ['Mon', 'Tues', "Weds', "Thurs', 'Fri']

    The values, of course, do not need to be literals.

  2. An array whose members can be computed by applying a mapping to a sequence of items can be constructed using an instruction such as:

    <xsl:array for-each="'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'"
           select="(., substring(., 1, 3))"/>

    This constructs an array with five members, each being a sequence of two strings: [('Monday', 'Mon'), ('Tuesday', 'Tue'), ('Wednesday', 'Wed'), ('Thursday', 'Thu'), ('Friday', 'Fri')]

    The values, of course, do not need to be literals.

    A more complex example might be:

    <xsl:array for-each="unparsed-text-lines('data.txt')"
           select="tokenize(.)"/>

    which creates an array with one member for each line of an input file, the relevant member being a sequence of words appearing on that line.

  3. An array with arbitrary content, that cannot readily be derived algorithmically from the items in a sequence. For example:
  4. <xsl:array>
       <xsl:array-member select="1"/>
       <xsl:array-member select="1, 2"/>
       <xsl:array-member select="1, 3"/>
       <xsl:array-member select="1, 2, 4"/>
       <xsl:array-member select="1, 5"/>
       <xsl:array-member select="1, 2, 3, 6"/>
       <xsl:array-member select="1, 7"/>
       <xsl:array-member select="1, 2, 4, 8"/>
       <xsl:array-member select="1, 3, 9"/>
       <xsl:array-member select="1, 2, 5, 10"/>
       <xsl:array-member select="1, 11"/>
       <xsl:array-member select="1, 2, 3, 4, 6, 12"/>
    </xsl:array>

    This returns an array of twelve members, each being a sequence of integers, for example the last member is the sequence (1, 2, 3, 4, 6, 12).

    Another example might be:

    <xsl:array>
       <xsl:for-each-group select="1 to 10" split-when="$next mod 5 lt $next mod 3">
         <xsl:array-member select="current-group()"/>
       </xsl:for-each-group>
    </xsl:array>

    This returns the array [ (1, 2, 3, 4), (5, 6, 7, 8, 9), 10 ].

The detailed rules follow.

  1. If the select attribute is present then the instruction must have empty content, except for xsl:fallback instructions which an XSLT 4.0 processor ignores.

    The result then depends on whether there is a for-each attribute.

    1. If the for-each attribute is absent, the result of the instruction is an array containing one singleton member for each item in the sequence selected by the select expression, retaining order.

    2. If the for-each attribute is present, then it is evaluated: let the result be R. For each item M in R, one array member is constructed, the value of that member being the result of evaluating the select expression with a focus in which the context item is M, the context position is the 1-based position of M within R, and the context size is the number of items in R.

  2. If the select attribute is absent, then the contained sequence constructor is used in its place. The effect depends on whether the for-each attribute is present.

    1. If the for-each attribute is absent, then the sequence constructor is evaluated. The result must be a sequence of zero or more zero-arity function items (typically but not necessarily constructed using the xsl:array-member instruction described below).

      The result of the xsl:array instruction contains one member for each of these zero-arity function items, the value of the array member being the result of evaluating the corresponding function item.

    2. If the for-each attribute is present, then it is evaluated: let the result be R. For each item M in R, one array member is constructed, the value of that member being the result of evaluating the contained sequence constructor with a focus in which the context item is M, the context position is the 1-based position of M within R, and the context size is the number of items in R.

The effect of the xsl:array-member instruction is to return a zero-arity function whose result, when called, is the result of evaluating either the select attribute or the contained sequence constructor, as appropriate.

Note:

The content of an array is effectively a sequence of sequences, which the XDM data model does not permit. Representing the value as a sequence of zero-arity functions provides a convenient workaround. When the select and for-each attributes are both absent, the result of the sequence constructor must be a sequence of zero-arity functions, each of which encapsulates the value of one member of the array. The xsl:array-member instruction provides a convenient and readable way of constructing the required zero-arity functions, but it is not necessary to use this instruction for the purpose; neither is xsl:array-member restricted to being used only for array construction.

As a general rule, xsl:array-member should be used if and only if the select and for-each attributes of xsl:array are both absent.

If the xsl:array instruction has a select attribute then the sequence constructor must be empty, except for any xsl:fallback instructions (which an XSLT 4.0 processor ignores) [see ERR XTSE3185].

If the xsl:array-member instruction has a select attribute then the sequence constructor must be empty, except for any xsl:fallback instructions (which an XSLT 4.0 processor ignores) [see ERR XTSE3185].

Example: Constructing an array whose members are single items

The following example constructs the array [1, 2, 3, 4, 5]:

<xsl:array select="1 to 5"/>

The following example constructs an array of text nodes:

<xsl:array select=".//text()"/>

The following example constructs an array by tokenizing a string:

<xsl:array select="tokenize('The cat sat on the mat')"/>

The result is the array [ "The", "cat", "sat", "on", "the", "mat" ].

The following example constructs an array containing items computed using nested instructions:

<xsl:array>
   <xsl:for-each-group select="0 to 19" group-adjacent=". idiv 4">
     <xsl:array-member select="string-join(current-group(), '-')"/>
   </xsl:for-each-group>
</xsl:array>

The result is the array [ "0-1-2-3", "4-5-6-7", "8-9-10-11", "12-13-14-15", "16-17-18-19" ].

 

Example: Constructing an array whose members are derived from the items in an input sequence

The following example constructs an array whose members are sequences:

<xsl:array for-each="para" select="distinct-values(tokenize(.))"/>

This returns an array with one member for each child paragraph, the content of the array member being the list of distinct words appearing in that paragraph.

The following example constructs an array in which the members are obtained by applying templates to the children of the context item:

<xsl:array for-each="*">                 
   <xsl:apply-templates select="."/>
</xsl:array>

The following example constructs a heterogeneous array containing a number of properties of the contexta supplied node, some of which are sequence-valued:

<xsl:array>
     <xsl:array-member select="local-name($node)"/>
     <xsl:array-member select="namespace-uri($node)"/>
     <xsl:array-member select="base-uri($node)"/>
     <xsl:array-member select="$node/namespace::*/string()"/>
     <xsl:array-member select="$node/@*/string()"/>  
</xsl:array>

 

Example: Constructing nested arrays

The xsl:array instruction can be nested. For example:

<xsl:array for-each="1 to 4">
   <xsl:array select="(.*10 to .*10 + 2)"/>
</xsl:array>

The result is [ [ 10, 11, 12], [ 20, 21, 22 ], [ 30, 31, 32 ], [ 40, 41, 42 ] ].

 

Example: Constructing arrays using template rules

Given a book containing chapters which in turn contain sections, the following code produces a nested array representing the (crude) word counts of the sections within each chapter:

<xsl:mode name="word-counts" on-no-match="shallow-skip">   
    <xsl:template match="book">
        <xsl:array>
            <xsl:apply-templates/>
        </xsl:array>
    </xsl:template>
    <xsl:template match="chapter">
        <xsl:array>
           <xsl:apply-templates/>
        </xsl:array>   
    </xsl:template>
    <xsl:template match="section">
        <xsl:sequence select="tokenize(.) => count()"/>
    </xsl:template>
</xsl:mode>

The result might be an array of the form [[842, 316], [450, 217], ...] indicating that the first section of the second chapter has a word count of 450.

 

Example: Constructing an array based on an existing array

The xsl:array instruction can be used in conjunction with the array:members function to construct an array from the members of an existing array. For example, the following code combines two arrays $A1 and $A2, and sorts the result:

<xsl:array 
   for-each="(array:members($A1), array:members($A2)) => sort(fn{count(?value)})"
   select="?value"/>

The following code transposes a regular nested array (such as [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ] ]) so the result is organized by columns rather than rows ([ [ 1, 4, 7 ], [ 2, 5, 8 ], [ 3, 6, 9 ] ]):

<xsl:array for-each="1 to array:size($input?1)">
   <xsl:variable name="index" select="."/>
   <xsl:array select="$input/*[$index]"/>
</xsl:array>