Maps and arrays
XTS uses an XPath 3.1 engine, so besides plain sequences you have two structured data types: arrays (ordered, indexable lists) and maps (key/value dictionaries). They can be nested freely, stored in variables, passed to functions, and built from your data. They are the idiomatic replacement for the old “dynamic variable name” trick.
Sequences, arrays, and maps
It helps to keep three things apart:
- A sequence is XPath’s flat, always-unnested list of items.
(1, 2, 3)is a sequence; sequences never contain other sequences. - An array is a single item that holds an ordered list, and arrays can
nest.
[1, 2, 3]is one array containing three members. - A map is a single item that holds key/value pairs.
map { 'a': 1 }has one entry.
Arrays
Build an array with a square-bracket constructor or the array { … }
constructor:
<SetVariable variable="nums" select="[10, 20, 30]"/>
<SetVariable variable="more" select="array { 1, 2, 3, 4 }"/>Read a member by position with the ? lookup operator (1-based), or get them all
with the ?* wildcard:
<Value select="$nums?2"/> <!-- 20 -->
<Value select="string-join(for $n in $nums?* return string($n), ', ')"/>Arrays nest, and lookups chain:
<SetVariable variable="people" select="[ map{'name':'Bob'}, map{'name':'Eve'} ]"/>
<Value select="$people?1?name"/> <!-- Bob -->Maps
Build a map with the map { … } constructor; keys and values are separated by a
colon, pairs by commas:
<SetVariable variable="prices" select="map { 'apple': 30, 'pear': 45 }"/>Look up a value by key with ?. If the key is not a simple name (a number, a
string with spaces, a computed value), put it in parentheses:
<Value select="$prices?apple"/> <!-- 30 -->
<Value select="$prices?('apple')"/> <!-- 30 -->The lookup operator ?
The ? operator works on both maps and arrays and is the everyday way to read
them:
| Expression | Meaning |
|---|---|
$map?key |
value for key key |
$map?('a key') |
value for a computed or non-name key |
$array?3 |
the third member (1-based) |
$array?* |
all members as a sequence |
$a?1?name |
chained lookup into nested structures |
Constructors ([ … ], map { … }, array { … }) and the ? operator are part
of the XPath syntax, so they work without any namespace declaration.
Function libraries
For anything beyond construction and lookup there are two standard function
libraries. Unlike the constructors, these functions are prefixed, so you must
declare their namespaces on the <Layout> root:
<Layout xmlns="urn:speedata.de/2021/xts/en"
xmlns:sd="urn:speedata.de/2021/xtsfunctions/en"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
xmlns:array="http://www.w3.org/2005/xpath-functions/array">Without the declaration you get Could not find namespace for prefix "map" (or
"array").
Common map functions: map:get, map:put, map:contains, map:keys,
map:size, map:remove, map:merge, map:entry, map:find, map:for-each.
<Value select="map:size($prices)"/> <!-- 2 -->
<Value select="string-join(map:keys($prices), ', ')"/> <!-- apple, pear -->
<SetVariable variable="prices" select="map:put($prices, 'plum', 25)"/>Common array functions: array:get, array:size, array:head, array:tail,
array:append, array:subarray, array:insert-before, array:remove,
array:put, array:reverse, array:join, array:flatten, array:for-each,
array:filter, array:sort, array:fold-left, array:fold-right.
<Value select="array:size($nums)"/> <!-- 3 -->
<Value select="array:get($nums, 1)"/> <!-- 10 -->These are the standard XPath 3.1 map: and array: functions; see the
goxml XPath documentation for the full
signatures.
map:put or array:append
return a new value rather than modifying the original – assign the result back
to a variable if you want to keep it.Building structures from data
Because arrays and maps are ordinary XPath values, you can build them from your input and reuse them:
<!-- a lookup table from the data -->
<SetVariable variable="byid"
select="map:merge(for $a in //article return map:entry($a/@id, $a/@name))"/>
<!-- later, resolve an id to a name -->
<Value select="$byid?('A-42')"/>See also
- XPath in XTS – where XPath is used and the
sd:layout functions. - Variables – storing values, including maps and arrays.
- Functions – passing structured values in and out.