saxon:deep-update

The saxon:deep-update instruction is used to make changes to the content of a structure of maps and arrays (which will typically have been obtained by applying the parse-json or json-doc function to JSON input).

Category: instruction
Content: none
Permitted parent elements: any XSLT element whose content model is sequence-constructor; any literal result element

Attributes

root

expression

An expression to select the root(s) of the tree(s) to be updated

select

expression

An expression to select the maps or arrays that are to be directly updated

action

expression

An expression to perform the update on the selected maps or arrays

Details

The effect, in outline, is to return a value that is the same as the value selected by the root expression, except that in the maps or arrays selected by the select expression, the specified action has been applied.

More detailed rules:

Internally, the way this works is that the root item is marked as a map/array that retains pedigree information. When downwards selections are made from a map/array with pedigree information, any maps or arrays that are selected in the content will also be marked as having pedigree information: specifically, this information holds the item's containing map or array, and its key within this map or array. At the leaf level, when a map/array with pedigree information is replaced, its known container can be updated to hold the new item in place of the old. This updating then percolates upwards to the root of the pedigree, and the updated root is returned in the result of the instruction.

Examples

Consider a JSON text holding details of customers, orders, and order-lines like this:

[ { "customer": "Jones the Baker", "orders" : [{ "order-no": 123, "date": "2017-02-03", "order-lines": [ { "product": "flour, 25Kg" "quantity": 1 }, { "product": "salt, 1Kg" "quantity": 3 } ] }, { "order-no": 456, "date": "2017-05-12", "order-lines": [ { "product": "butter, 10Kg" "quantity": 2 }, { "product": "yeast, 100g" "quantity": 5 } ] }] }, { "customer": "Evans the Butcher", .... } ]

And suppose we want to double the quantity of flour ordered by Jones. This can be done as follows:

<xsl:variable name="in" select="json-doc('customers.json')"/> <xsl:variable name="updated" as="array(*)"> <saxon:deep-update root = "$in" select = "?*[?customer = 'Jones the Baker'] ? orders?*[?order-no = 123] ? order-lines?*[contains(?product, 'flour')]" action = "map:put(., 'quantity', ?quantity * 2)"/> </xsl:variable> <xsl:value-of select="serialize($updated, map{'method':'json', 'indent':true()})"/>