XPath 3.1 Maps and Arrays: Bridging XML and JSON

XPath 3.1 introduced map and array data types to expand the XQuery and XPath Data Model (XDM) beyond traditional hierarchical XML nodes. This article explains the syntax and behavior of XPath 3.1 maps and arrays, demonstrates how they directly model JSON structures, and highlights how these additions allow developers to seamlessly query, transform, and integrate both XML and JSON within a single processing pipeline.

The Need for Maps and Arrays in XPath 3.1

Prior to XPath 3.1, the data model relied entirely on sequences of atomic values and XML nodes (elements, attributes, text nodes). While sequences handled ordered lists of XML items well, they lacked two critical capabilities required for modern data processing:

  1. Nested collections: Standard XPath sequences cannot contain other sequences; any nested sequence automatically flattens.
  2. Key-value lookups: Associative lookups required searching XML attributes or elements using predicates, which was inefficient for arbitrary key-value mappings.

With the widespread adoption of JSON in web APIs and modern architectures, XPath required native structures capable of modeling JSON objects and JSON arrays without converting everything into synthetic XML trees. The W3C resolved this in XPath 3.1 by adding map and array item types as first-class citizens in the data model.

The Array Data Type

An XPath 3.1 array is an ordered list of items where each entry—termed a member—can be any sequence of zero or more items. Unlike standard sequences, arrays do not flatten when nested inside other arrays.

Syntax and Creation

Arrays can be created using the square-bracket constructor or the array keyword:

(: Square-bracket constructor :)
[ "apple", "banana", "cherry" ]

(: Array containing nested sequences :)
[ (1, 2, 3), ("a", "b"), [] ]

(: Array constructor using a sequence :)
array { 1 to 5 }

Accessing Array Members

Array members are 1-indexed. Members can be retrieved using functional invocation or the lookup operator (?):

let $fruits := [ "apple", "banana", "cherry" ]
return $fruits(1)       (: Returns "apple" :)

(: Using the lookup operator :)
$fruits?2              (: Returns "banana" :)

(: Wildcard lookup to extract all members as a sequence :)
$fruits?*              (: Returns ("apple", "banana", "cherry") :)

The Map Data Type

An XPath 3.1 map is a collection of key-value pairs. Keys must be atomic values (such as strings, integers, or URIs), while values can be any arbitrary sequence of items, including nodes, arrays, or other maps.

Syntax and Creation

Maps are created using the map constructor:

map {
  "name": "Jane Doe",
  "id": 1042,
  "active": true(),
  "roles": [ "admin", "editor" ]
}

Accessing Map Entries

Values within a map can be retrieved using functional invocation, string key references, or the lookup operator:

let $user := map { "name": "Jane Doe", "id": 1042 }
return $user("name")    (: Returns "Jane Doe" :)

(: Using the lookup operator :)
$user?id               (: Returns 1042 :)

Bridging the Gap Between XML and JSON

The inclusion of map and array data types creates a direct 1:1 conceptual mapping between JSON and XPath data models:

Native JSON Parsing and Serialization

XPath 3.1 introduces built-in functions that convert raw JSON strings directly into these native structures:

let $json := '{"status": "ok", "items": [10, 20, 30]}'
let $data := parse-json($json)
return $data?items?1   (: Returns 10 :)

Unified Multi-Format Processing

Because maps and arrays are native XDM items, they can hold XML nodes, and XML nodes can reference or generate maps and arrays. In environments supporting XPath 3.1 (such as XSLT 3.0 or XQuery 3.1 processors), a developer can read an XML document, query a REST JSON endpoint using fn:json-doc(), combine the data structures using standard path expressions, and output either XML or JSON without intermediary third-party conversion libraries.