Given input JSON that is "sparsely populated" with values, such as:
{
"a": {
"b": {},
"c": {
"d": {
"e": "value",
"f": {}
}
},
"g": 123
},
"h": {
"i": [
{},
{"j": "value"}
],
"k": "value",
"l": {
"m": {},
"n": {}
}
},
"o": {
"p": [
{},
{}
],
"q": {
"r": {},
"s": {}
}
}
}
(This is just a simplified representative example. Actual structure can be deeper than this.)
I want to use Mike Farah's yq to prune all "value-less" keys, and output:
a:
c:
d:
e: value
g: 123
h:
i:
- j: value
k: value
The following command produces the desired result, but involves repeating the same expression, where the number of repetitions depends on the structure of the input JSON:
yq -p=json -o=yaml --from-file=yq-expression.txt input.json
where yq-expression.txt
contains:
# Recursively delete empty objects
del( .. | select((kind == ("map", "seq")) and (length == 0))) |
del( .. | select((kind == ("map", "seq")) and (length == 0))) |
del( .. | select((kind == ("map", "seq")) and (length == 0)))
(In practice, (kind == ("map", "seq")) and (length == 0)
is overkill; just length == 0
is enough.)
With the example input JSON cited here, if I omit one of those repetitions, the output isn't completely "pruned".
I'd like a concise expression that reliably (without manual, arbitrary, hard-coded repetition) produces the desired result, regardless of the depth of the structure of the input JSON.
Using mikefarah/yq v4.40.1+, you could traverse the tree with ..
, filter for all scalars, and rebuild the tree only with those paths:
(.. | select(kind == "scalar")) as $i ireduce(null; setpath($i | path; $i))
a:
c:
d:
e: value
g: 123
h:
i:
- null
- j: value
k: value
Note: To fully preserve the value under .h.i[1].j
, .h.i[0]
has to exist, hence the null
value in the first position of that array. To additionally remove all null
values from arrays, append another line scanning for arrays (aka seq), and filter for non-null
values:
(.. | select(kind == "scalar")) as $i ireduce(null; setpath($i | path; $i)) |
(.. | select(kind == "seq")) |= map(select(. != null))
a:
c:
d:
e: value
g: 123
h:
i:
- j: value
k: value