Arrays

XPath 3.1 introduced arrays as a new data type, with limited support in XSLT 3.0. XPath 4.0 makes no changes to the data model for arrays, but introduces additional convenience functions.

The main reason arrays were introduced was to allow JSON data structures to be represented faithfully. However there are many other ways you can take advantage of arrays.

Arrays differ from sequences in a number of ways:

Arrays, like all other XDM values, are immutable. When you append or replace or remove a member entry in an array, you get a new array; the original is unchanged. The Saxon implementation uses a "persistent immutable" data structure under the covers, to ensure that making a small change to an array (such as replacing a single member) does not require copying the entire array.

As with sequences and maps, arrays do not have an intrinsic type of their own, but rather have a type that can be inferred from what they contain. An array conforms to the type array(T) if all of its members are of type T. For example if the members are all strings, then the array conforms to the type array(xs:string).

There are several ways to create an array:

Array functions

The summary of the full list of functions that operate on arrays is as follows; for full details see the Functions library. The prefix array represents the namespace URI http://www.w3.org/2005/xpath-functions/array.

Arrays: technical implementation details

Internally Saxon (from release 9.9) uses two implementations of arrays.

The first implementation, SimpleArrayItem, is backed by a Java ArrayList<Sequence>. An array constructor (either [x,y,z] or array{a,b,c}) will always deliver a SimpleArrayItem. This is economical on storage and has good performance for accessing specific items by index position, or for scanning the entire array. It is less well suited to incremental modification.

The other implementation, PersistentArrayItem, is backed by a persistent (immutable) list implemented as a tree structure. This makes it possible to add, replace, or remove entries in constant time without copying the entire array.

The result of operations such as array:put(), array:insert-before(), and array:remove() is always a PersistentArrayItem, even if the input is a SimpleArrayItem. Converting one to the other takes time proportional to the size of the array.

The result of array:filter(), array:for-each(), array:for-each-pair(), and array:reverse() is always a SimpleArrayItem, even if the input is a PersistentArrayItem. In cases where an array goes through a construction phase and is then used heavily for retrieval-only access, it might be worth forcing it back to a SimpleArrayItem at the end of the construction phase: this can be achieved by means of a call on array:filter() with a predicate that selects all members.

Changes in XPath 4.0

XPath 4.0 and XSLT 4.0 introduce some changes for array items:

  • A number of new functions are added, and existing functions have been extended, as described above.

  • A variant of the for expression (FLWOR expression in XQuery) is introduced, allowing iteration over arrays. For example, for member $m in [<e/>, <f/>, <g/>] return local-name($m) returns the sequence ("e", "f", "g").

  • The values of the members of an array can be bound to separate variables using a let expression. For example, let [$x, $y] := $array return ... is equivalent to let $x := $array?1, $y := $array?2 return ....

  • Trees of maps and arrays (called JTrees, made up of JNodes) can be processed using path expressions, in the same way as trees of XML nodes (now called XNodes when there is a need to make the distinction).

  • In XSLT, the xsl:array and xsl:array-member instructions are introduced.