XQuery 3.1 introduced several JSON functions. I was wondering if these functions were designed with advanced JSON editing in mind.
As far as I can tell, these functions only work for simple JSONs, like for instance...
let $json:={"a":1,"b":2} return map:put($json,"c",3)
{
"a": 1,
"b": 2,
"c": 3
}
and
let $json:={"a":1,"b":2,"c":3} return map:remove($json,"c")
{
"a": 1,
"b": 2
}
The moment the JSON gets a bit more complex:
let $json:={"a":{"x":1,"y":2},"b":2} return map:put($json?a,"z",3)
{
"x": 1,
"y": 2,
"z": 3
}
let $json:={"a":{"x":1,"y":2,"z":3},"b":2} return map:remove($json?a,"z")
{
"x": 1,
"y": 2
}
Obviously map:put()
and map:remove()
do exactly what you tell them to do; select the "a"-object and add or remove an attribute.
However, when I want to edit a JSON document, I'd like to edit the entire document. And as far as I know that's not possible with the current implementation. Or is it? At least something like map:put($json,$json?a?z,3)
or map:remove($json,$json?a?z)
doesn't work.
For the removal of the "z"-attribute I did come up with a custom recursive function (which only works in this particular use-case)...
declare function local:remove($map,$key){
if ($map instance of object()) then
map:merge(
map:keys($map)[.!=$key] ! map:entry(.,local:remove($map(.),$key))
)
else
$map
};
let $json:={"a":{"x":1,"y":2,"z":3},"b":2} return
local:remove($json,"z")
...with the expected output...
{
"a": {
"x": 1,
"y": 2
},
"b": 2
}
...but I wasn't able to create a custom "add"-function.
I imagine advanced JSON editing can be done with some pretty advanced custom functions, but instead I would very much like to see that something like map:put($json,$json?a?z,3)
would work, or otherwise an extra option which lets map:put()
put out the entire JSON document, like map:put($json?a?z,3, <extra-option> )
.
Or... I'd have to settle with the notion that XQuery isn't the right choice of course.
You're correct that doing what I call deep update of a map is quite difficult with XQuery 3.1 (and indeed XSLT 3.0) as currently defined. And it's not easy to define language constructs with clean semantics. I attempted to design a construct as an XSLT extension instruction - see https://saxonica.com/documentation10/index.html#!extensions/instructions/deep-update -- but I don't think its anywhere near a perfect solution.