Search code examples
jsonjsoniq

JSONiq - how do you convert an array to a sequence?


Using the JSONiq to JavaScript implementation of JSONiq, say I have an array

let $a := [1,2,3]

I'd like to get the elements as a sequence, but all of these return the array itself -

return $a()
return $a[]
return members($a)

What is the correct way to extract the members of the array?


My ultimate goal is to convert objects in an array to strings, like so -

let $updates := [
  {"address": "%Q0.1", "keys": ["OUT2", "output.2"], "value": 0},
  {"address": "%Q0.7", "keys": ["OUT8", "output.8"], "value": 1}
]

for $update in $updates()
return "<timestamp>|address|" || $update.address

in order to convert an array of JSON objects to a set of strings like <timestamp>|address|%Q0.7, etc


Edit: Using Zorba the $a() syntax seems to work okay - is it an issue with the node jsoniq parser?

e.g.

jsoniq version "1.0";

let $updates := [
  {"address": "%Q0.1", "keys": ["OUT2", "output.2"], "value": 0},
  {"address": "%Q0.7", "keys": ["OUT8", "output.8"], "value": 1}
]

for $update in $updates()
return current-dateTime() || "|address|" || $update.address

returns

2021-02-19T23:10:13.434273Z|address|%Q0.1 2021-02-19T23:10:13.434273Z|address|%Q0.7


Solution

  • In the core JSONiq syntax, an array is turned into a sequence (i.e., its members are extracted) with an empty pair or square brackets, like so:

    $array[]
    

    Example:

    [1, 2, 3, 4][]
    

    returns the sequence:

    (1, 2, 3, 4)
    

    This means that the query would be:

    let $updates := [
      {"address": "%Q0.1", "keys": ["OUT2", "output.2"], "value": 0},
      {"address": "%Q0.7", "keys": ["OUT8", "output.8"], "value": 1}
    ]
    
    for $update in $updates[]
    return "<timestamp>|address|" || $update.address
    

    The function-call-like notation with an empty pair of parenthesis dates back to JSONiq's early days, as it was primarily designed as an extension to XQuery and maps and arrays were navigated with function calls ($object("foo"), $array(), $array(2)). As JSONiq started having its own life, though, more user-friendly and intuitive syntax for JSON navigation was introduced:

    $array[[1]]
    

    for array member lookup given a position

    $object.foo
    

    for object lookup given a key and

    $array[]
    

    for array unboxing.

    While the JSONiq extension to XQuery still exists for scenarios in which users need both JSON and XML support (and is supported by Zorba 3.0, IBM Websphere, etc), the core JSONiq syntax is the main one for all engines that specifically support JSON, like Rumble.

    Some engines (including Zorba 3.0) support both the core JSONiq syntax and the JSONiq extension to XQuery, and you can pick the one you want with a language version declaration:

    jsoniq version "1.0";
    [1, 2, 3, 4][]
    

    vs.

    xquery version "3.0";
    [1, 2, 3, 4]()
    

    Zorba is relatively lenient and will probably even accept both () and [] in its core JSONiq implementation.

    (Warning: Zorba 2.9 doesn't support the latest core JSONiq syntax, in particular the try.zorba.io page still runs on Zorba 2.9. You need to download Zorba 3.0 and run it locally if you want to use it).

    A final note: JSON navigation works in parallel, on sequences of arrays and objects, too:

    (
      {"foo":1},
      {"foo":2},
      {"foo":3},
      {"foo":4}
    ).foo
    

    returns

    (1, 2, 3, 4)
    

    while

    (
      [1, 2],
      [3, 4, 5],
      [6, 7, 8]
    )[]
    

    returns

    (1, 2, 3, 4, 5, 6, 7, 8)
    

    This makes it very easy and compact to navigate large sequences:

    $collection.foo[].bar[[1]].foobar[].foo