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 can be nested (an array can have other arrays as its members). In fact the members of an array can be arbitrary XDM values, including nodes, atomic items, sequences, functions, and maps. A member of an array can also be an empty sequence.
-
An array is a single item, so you can have a sequence of arrays.
-
As with sequences, the members of an array are addressed by integers in the range 1 to N, where N is the length of the array. However, unlike sequences, any attempt to access a member using an out-of-range index is a dynamic error (
FOAY0001). -
To access the Nth member of an array, use the syntax
$array($N). This works because an array is a function: given an integer$Nas the argument, this function returns the member in position$N. -
Alternatively, you can also use a so-called lookup expression:
$array?1is equivalent to $array(1). The subscript can be an integer literal, or any expression in parentheses (for example$array?($i+1)), and in XPath 4.0 it can also be a variable reference:$array?$i. -
Operators and functions designed to work on sequences, such as
count(), for expressions, filter expressions,head(),tail(),remove(),insert()and so on, do not work as you might expect on arrays. They don't return an error, because an array is a sequence of length one, but they don't return the result you might have expected. Instead, there is a library of functions available to perform analogous operations on arrays.However, operators designed to work on sequences of atomic items will also produce useful results when applied to arrays of atomic items. This is because atomizing an array produces the corresponding sequence. So, for example,
sum([1,2,3,4])returns 10, as doessum([[1,2], [3,4]]).
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:
-
If the number of members is known, you can use the constructor syntax
[ value, value, value ]. Here the values can be any "simple expression" (an expression not containing a top-level comma). If the values are all known statically, you might write:[1, 2, "a", "b"]. You can use this construct anywhere an XPath expression can be used, for example in theselectattribute of an xsl:variable element. The members do not need to be single items: for example[(), 1, 2, 5 to 10]constructs an array with four members, the members being sequences of length 0, 1, 1, and 6 respectively. The construct[]returns an empty array. -
If the number of members is unknown, but if you know that each member of the array will be a single item, you can use the construct
array{ value }wherevalueis any sequence. For example,array{(), 1, 2, 5 to 10}constructs an array with eight members, these being the single integers 1, 2, 5, 6, 7, 8, 9, and 10.
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.
-
array:append: adds one new member to the end of an array. For example,array:append([], 5)returns[5]. Since XPath 3.1. -
array:build: Returns an array obtained by evaluating the supplied function once for each item in the input sequence. New in XPath 4.0. -
array:empty: Returnstrueif the supplied array contains no members. New in XPath 4.0. -
array:filter: returns those members of an array that satisfy some condition, expressed as a function. For example,array:filter(array{1 to 5}, function($x){$x mod 2 = 1})returns[1, 3, 5]. Since XPath 3.1. -
array:flatten: replaces an array by the sequence-concatenation of its members, recursively. For example,array:flatten(([1], [2 to 4], [3, [4, 5]]))returns(1, 2, 3, 4, 3, 4, 5). Since XPath 3.1. -
array:fold-left: applies a function cumulatively to successive members of the array: each call is applied to two arguments, being the value so far, and the next member of the array. For example,array:fold-left(array{1 to 5}, 0, function($x, $y){$x + $y})returns15, whilearray:fold-left(array{1 to 3}, [], function($x, $y){[$x, $y]})returns[[[[], 1], 2], 3]. Since XPath 3.1. -
array:fold-right: applies a function cumulatively to successive members of the array: each call is applied to two arguments, being the next member of the array, and the result of applying the function to the remainder of the array. For example,array:fold-right(array{1 to 5}, 0, function($x, $y){$x + $y})returns15, whilearray:fold-right(array{1 to 3}, [], function($x, $y){[$x, $y]})returns[1, [2, [3, []]]]. Since XPath 3.1. -
array:foot: Returns the last member of an array. New in XPath 4.0. -
array:for-each: applies a function to each member of an array, and returns an array containing the results. For example,array:for-each(array{1 to 5}, function($x){$x + 1})returns[2, 3, 4, 5, 6]. Since XPath 3.1. -
array:for-each-pair: applies a function to pairs of corresponding items from two supplied arrays. For example,array:for-each-pair(['x', 'y', 'z'], [1, 2, 3], concat#2)returns['x1', 'y2', 'z3']. Since XPath 3.1. -
array:get: returns the member at a given position (starting from 1). For example,array:get([3, 4, 5], 2)returns4. Since XPath 3.1. -
array:head: returns the first member of the array. For example,array:head([1 to 5, 1 to 10])returns(1 to 5)(a sequence, not an array). Since XPath 3.1. -
array:index-of: Returns a sequence of positive integers giving the positions within the array$arrayof members that are equal to$target. New in XPath 4.0. -
array:index-where: Returns the positions in an input array of members that match a supplied predicate. New in XPath 4.0. -
array:insert-before: inserts a new member at a given position. For example,array:insert-before([1, 2, 3, 4], 3, ())returns[1, 2, (), 3, 4]. Since XPath 3.1. -
array:items: Returns the sequence concatenation of the members of an array. New in XPath 4.0. -
array:join: Joins a number of arrays end-to-end to create a new array. For example,array:join(([1], [2 to 4], [3, [4, 5]]))returns[1, (2, 3, 4), 3, [4, 5]]. Since XPath 3.1. -
array:members: Delivers the contents of an array as a sequence of value records. New in XPath 4.0. -
array:of-members: Constructs an array from the contents of a sequence of value records. New in XPath 4.0. -
array:put: replaces the member at a given position. For example,array:put([4, 5, 6], 2, 8)returns[4, 8, 6]. Since XPath 3.1. -
array:remove: removes the member at a given position. For example,array:remove([4, 5, 6], 2)returns[4, 6]. Since XPath 3.1. -
array:reverse: reverses the order of members. For example,array:reverse([[1,2], [3,4]])returns[[3,4], [1,2]]. Since XPath 3.1. -
array:size: returns the number of members in the array. For example,array:size([[1,2], [3,4]])returns2. Since XPath 3.1. -
array:slice: Returns an array containing selected members of a supplied input array based on their position. New in XPath 4.0. -
array:sort: sorts the members of an array, either by their own atomic item, or by the result of applying a function to compute a sort key. A collation can also be specified. For example,array:sort([4, 8, 2])returns[2, 4, 8]. Since XPath 3.1. -
array:sort-by: Sorts a supplied array, based on the value of a number of sort keys supplied as functions. New in XPath 4.0. -
array:sort-with: Sorts a supplied array, according to the order induced by the supplied comparator functions. New in XPath 4.0. -
array:split: Delivers the contents of an array as a sequence of single-member arrays. New in XPath 4.0. -
array:subarray: returns members of the array starting at a specified position, either to the end of the array or up to a specified length. For example,array:subarray([1, 2, 3, 4], 2)returns[2, 3, 4], whilearray:subarray([1, 2, 3, 4], 2, 2)returns[2, 3]. Since XPath 3.1. -
array:tail: removes the first member from an array. For example,array:tail([1 to 5, 1 to 10])returns[1 to 10]. Since XPath 3.1. -
array:trunk: Returns an array containing all members except the last from a supplied array. New in XPath 4.0.
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
forexpression (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
letexpression. For example,let [$x, $y] := $array return ...is equivalent tolet $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:arrayandxsl:array-memberinstructions are introduced.