In the latest jq version 1.6 there is a feature Destructuring Alternative Operator: ?// I am trying to use this to parse my clumsily converted XML.
This is the simplified example I have been playing with on jq play:
{"data":[
{"fruit":"orange","details": {"colour":"orange"}},
{"fruit":"apple", "details": [{"colour":"red"},{"colour":"green"}]}
]}
The key point is sometimes details
is an object and sometimes it's an array of objects, and to quote from the doc "We can use the destructuring alternative operator to handle this structural change simply"
If I change the input data so details
is always an array I can easily create the output I want
.data[] | "\(.fruit) - \(.details[].colour)"
{"data":[
{"fruit":"orange","details": [{"colour":"orange"}]},
{"fruit":"apple", "details": [{"colour":"red"},{"colour":"green"}]}
]}
"orange - orange"
"apple - red"
"apple - green"
However using the original data with ?// the best I can come up with is:
.data[] as {$fruit, details: $colour} ?// {$fruit, details: $colour} | "\($fruit) - \($colour)"
"orange - {\"colour\":\"orange\"}"
"apple - [{\"colour\":\"red\"},{\"colour\":\"green\"}]"
and this (which is pretty much a copy of one of the examples):
.data[] as {$fruit, details: {$colour}} ?// {$fruit, details: [{$colour}]} | "\($fruit) - \($colour)"
"orange - orange"
"apple - red"
There are solutions using if else but I am particularly interested in how this feature works and what I need to do to get it to create the output I want.
One way to generate the output you expect is by using ? //
rather than ?//
:
.data[]
| (.details | (.colour? // (.[] | .colour))) as $colour
| "\(.fruit) - \($colour)"
As for ?//
, you might be barking up the wrong tree: the destructuring-alternative operator is not stream-oriented. That is, when a non-empty array is matched with [$foo], $foo will only match the first item in the array, not the items in sequence.
However, if you really wanted to use ?//
, for your particular case you could write:
.data[]
| .details as [$colour1, $colour2] ?// $colour1
| "\(.fruit) - \($colour1|.colour)",
"\(.fruit) - \($colour2//empty|.colour)"