Version 5.8.0

# Arrays and Maps

The speedata Publisher supports arrays and maps as native data structures. This allows ordered lists and key-value mappings to be used directly in XPath expressions — without the detour of dynamically generated variable names.

The constructors (`[...]`, `array { ... }`, `map { ... }`) and the lookup operator (`?`) can be used directly. To use functions like `array:size()`, `map:keys()` etc., the corresponding namespaces must be declared in the root element:

    <Layout xmlns="urn:speedata.de:2009/publisher/en"
        xmlns:sd="urn:speedata:2009/publisher/functions/en"
        xmlns:array="http://www.w3.org/2005/xpath-functions/array"
        xmlns:map="http://www.w3.org/2005/xpath-functions/map">

The prefixes `array` and `map` can be chosen freely, but the namespace URIs must be exactly as shown.

## Arrays

An array is an ordered collection of values. Each element (“member”) can be any XPath value — numbers, strings, or even other arrays and maps.

### Creating arrays

Square brackets — each expression becomes a member:

    <SetVariable variable="colors" select="['red', 'green', 'blue']"/>
    <SetVariable variable="numbers" select="[10, 20, 30]"/>
    <SetVariable variable="empty" select="[]"/>

Curly constructor — a sequence is split into individual members:

    <SetVariable variable="one_to_five" select="array { 1 to 5 }"/>

The result is an array with five members: 1, 2, 3, 4, 5.

### Accessing array elements

The lookup operator `?` accesses a member by index (1-based):

    <Value select="$colors?1"/>   <!-- returns: red -->
    <Value select="$colors?3"/>   <!-- returns: blue -->

The wildcard `?*` returns all members as a flat sequence:

    <Value select="string-join($colors?*, ', ')"/>
    <!-- returns: red, green, blue -->

### Array functions

All array functions are in the `array:` namespace. Arrays are immutable – functions like `array:put()` or `array:append()` return a new array, the original remains unchanged.

`array:size(<array>)`
  Number of members. `array:size([1, 2, 3])` returns `3`.
`array:get(<array>, <position>)`
  Return the member at the given position. `array:get(['a', 'b', 'c'], 2)` returns `b`.
`array:append(<array>, <value>)`
  New array with appended member. `array:append([1, 2], 3)` returns `[1, 2, 3]`.
`array:put(<array>, <position>, <value>)`
  New array with replaced member at the given position.
`array:remove(<array>, <position>)`
  New array without the member at the given position.
`array:subarray(<array>, <start>[, <length>])`
  Sub-array starting at the given position.
`array:join(<array-sequence>)`
  Concatenate a sequence of arrays into a single array.
`array:flatten(<array>)`
  Recursively flatten nested arrays into a flat sequence. `array:flatten([1, [2, 3]])` returns the sequence `1, 2, 3`.

## Maps

A map is a collection of key-value pairs. Keys are atomic values (typically strings or numbers), values can be anything.

### Creating maps

    <SetVariable variable="prices"
        select="map { 'apple': 1.50, 'pear': 2.30, 'cherry': 4.90 }"/>
    <SetVariable variable="empty" select="map {}"/>

Keys and values are separated by `:`, entries by `,`.

### Accessing map entries

The lookup operator `?` accesses entries by key name:

    <Value select="$prices?apple"/>   <!-- returns: 1.5 -->
    <Value select="$prices?cherry"/>  <!-- returns: 4.9 -->

The wildcard `?*` returns all values:

    <Value select="count($prices?*)"/>  <!-- returns: 3 -->

### Map functions

All map functions are in the `map:` namespace and return new maps.

`map:size(<map>)`
  Number of entries. `map:size(map { 'a': 1, 'b': 2 })` returns `2`.
`map:keys(<map>)`
  Return the keys as a sequence.
`map:get(<map>, <key>)`
  Return the value for the key. Empty sequence if the key does not exist.
`map:contains(<map>, <key>)`
  `true()` if the key exists.
`map:put(<map>, <key>, <value>)`
  New map with inserted or replaced entry.
`map:remove(<map>, <key>)`
  New map without the entry.
`map:merge(<map-sequence>)`
  Merge a sequence of maps. For duplicate keys, the last value wins.
`map:entry(<key>, <value>)`
  Create a map with a single entry.

## Practical examples

### Product catalog with prices

    <SetVariable variable="prices" select="map {
        'SKU-001': 29.95,
        'SKU-002': 79.00,
        'SKU-003': 149.90
    }"/>

    <Record element="product">
        <PlaceObject>
            <Textblock>
                <Paragraph>
                    <Value select="@name || ': ' || $prices?(@sku) || ' EUR'"/>
                </Paragraph>
            </Textblock>
        </PlaceObject>
    </Record>

### Color mapping

    <SetVariable variable="colors" select="map {
        'error': 'red',
        'warning': 'yellow',
        'ok': 'green'
    }"/>

    <Value select="$colors?($status)"/>

### Building a collection

Since arrays and maps are immutable, collections are built incrementally:

    <SetVariable variable="entries" select="[]"/>

    <SetVariable variable="entries"
        select="array:append($entries, 'First entry')"/>
    <SetVariable variable="entries"
        select="array:append($entries, 'Second entry')"/>

#### On this page