Maps in XPath
An important new feature in XPath 3.1 is the definition of maps. (This feature is in fact included in the XPath 3.0 implementation in Saxon, and thus was available as an advanced feature since Saxon 9.5, before the full implementation of XPath 3.1 in Saxon 9.7).
A map is a new kind of XDM item (alongside nodes and atomic values). In fact, a map is a kind of function: you can think of it as a function defined extensionally (by tabulating the value of the function for all possible arguments) rather than intensionally (by means of an algorithm).
A map is a set of entries. Each entry is a key-value pair. The key is always an atomic value. The value is any XDM value: a sequence of nodes, atomic values, functions, or maps.
Maps, like sequences, are immutable. When you add an entry to a map, you get a new map; the original is unchanged. Saxon provides an efficient implementation of maps that achieves this without copying the whole map every time an entry is added.
Also like sequences, maps do not have an intrinsic type of their own, but rather have a
type that can be inferred from what they contain. A map conforms to the type map(K,
V)
if all the keys are of type K
and all the values are of type
V
. For example if the keys are all strings, and the values are all
employee
elements, then the map conforms to the type map(xs:string,
element(employee))
.
There are several ways to create a map:
-
If the number of entries is known, you can use the constructor syntax
map { key : value, key : value, ... }
. (A previous version of the spec used ":=
" rather than":"
as the separator, since Saxon 9.7 this alternative is no longer supported.) Here the keys and values can be any "simple expression" (an expression not containing a top-level comma). If the keys and values are all known statically, you might write:map { "a" : 1, "e" : 2, "i" : 3, "o" : 4, "u" : 5 }
. You can use this construct anywhere an XPath expression can be used, for example in theselect
attribute of an xsl:variable element. -
The function map:merge() takes a number of maps as input, and combines them into a single map. This can be used to construct a map where the number of entries is not known statically: for example
map:merge(for $i in 1 to 10 return map{$i : codepoints-to-string($i)})
.(In previous working drafts, this function was named
map:new()
, but this name is no longer supported since Saxon 9.7.) -
A single-entry map can also be constructed using the function
map:entry($key, $value)
.
It is also possible to create maps using the XSLT instructions xsl:map and xsl:map-entry.
Given a map $M
, the value corresponding to a given key $K
can be
found either by invoking the map as a function: $M($K)
, or by calling
map:get($M, $K)
.
The summary of the full list of functions that operate on maps is as follows; for full
details see the Functions Library. The prefix
map
represents the namespace URI
http://www.w3.org/2005/xpath-functions/map
.
-
map:merge($maps as map(*)) as map(*)
: takes a sequence of maps as input and combines them into a single map. -
map:size($map as map(*)) as xs:integer
: returns the number of entries (key/value pairs) in a map. -
map:keys($map as map(*)) as xs:anyAtomicType*
: returns the keys that are present in a map, in unpredictable order. -
map:contains($map as map(*), $key as xs:anyAtomicType) as xs:boolean
: returns true if the given key is present in the map. -
map:get($map as map(*), $key as xs:anyAtomicType) as item()*
: returns the value associated with the given key if present, or the empty sequence otherwise. Equivalent to calling$map($key)
. -
map:put($map as map(*), $key as xs:anyAtomicType, $value as item()*) as map(*)
: adds an entry to a map, which replaces any existing entry for the same key, returning a new map. -
map:entry($key as xs:anyAtomicType, $value as item()*)
: creates a singleton map. Useful as an argument tomap:merge()
. -
map:remove($map as map(*), $key as xs:anyAtomicType) as map(*)
: removes an entry from a map (if it was present), returning a new map; if not present, returns the existing map unchanged. -
map:for-each($map as map(*), $f as function(xs:anyAtomicType, item()) as item()*) as item(*)
: processes every key/value pair in a map by applying the given function, returning the results as a sequence in unpredictable order.