Reputation: 844
I want to extract the subtree containing the focused window from i3-msg -t get_tree
with jq
. I know the focused window can be found with
i3-msg -t get_tree | jq ".. | (.nodes? // empty)[] | select(.focused == true)"
A simple example would be:
{
"node": [
{
"node": {
"foo": "bar"
}
},
{
"node": {
"foo": "foo"
}
}
]
}
And the output should if searching for a node
containg .foo == "bar"
should return
{
"node": [
{
"node": {
"foo": "bar"
}
}
]
}
But I can't seem to find a proper method to extract the subtree spanning from the root to this node.
Upvotes: 1
Views: 1135
Reputation: 2030
.node |= map(select(.node.foo == "bar"))
This concept is referred to as Update assignment
Upvotes: 2
Reputation: 116780
The original question has two distinct sub-questions, one related to the use of ..
without reference to a posted JSON sample, and the other based on a specific type of JSON input. This response uses a strategy based on using paths
along the lines of:
reduce pv as [$p,$v] (null; setpath($p; $v))
This may or may not handle arrays as desired, depending in part on what is desired. If null
values in arrays are not wanted in general, then adding a call to walk/1
as follows would be appropriate:
walk(if type == "array" then map(select(. != null)) else . end)
Alternatively, if the null
values that are present in the original must be preserved, the strategy detailed in the Appendix below may be used.
(1) Problem characterized by using ..
def pv:
paths as $p
| getpath($p)
| . as $v
| (.nodes? // empty)[] | select(.focused == true)
| [$p,$v];
reduce pv as [$p,$v] (null; setpath($p; $v))
As mentioned above, to eliminate all the nulls in all arrays, you could tack on a call to walk/1
. Otherwise, if the null
values inserted in arrays by setpath
to preserve aspects of the original structure, see the Appendix below.
(2) For the sample JSON, the following suffices:
def pv:
paths as $p
| getpath($p)
| . as $v
| (.node? // empty) | select(.foo == "bar")
| [$p,$v];
reduce pv as [$p,$v] (null; setpath($p; $v))
For the given sample, this produces:
{"node":[{"node":{"foo":"bar"}}]}
For similar inputs, if one wants to eliminate null
values from arrays, simply tack on the call to walk/1
as before; see also the Appendix below.
If the null
values potentially inserted into arrays by setpath
to preserve the original structure are not wanted, the simplest would be to change null
values in the original JSON to some distinctive value (e.g. ":null:"), perform the selection, trim the null
values, and then convert the distinctive value back to null
.
For example, consider this variant of the foo/bar example:
{
"node": [
{
"node": {
"foo": "foo0"
}
},
{
"node": {
"foo": "bar",
"trouble": [
null,
1,
null
]
}
},
{
"node": {
"foo": "foo1"
}
},
{
"node": {
"foo": "bar",
"trouble": [
1,
2,
3
]
}
}
],
"nodes": [
{
"node": {
"foo": "foo0"
}
},
{
"node": {
"foo": "bar",
"trouble": [
null,
1,
null
]
}
}
]
}
Using ":null:" as the distinctive value, the following variant of the "main" program previously shown for this case may be used:
walk(if type == "array" then map(if . == null then ":null:" else . end) else . end)
| reduce pv as [$p,$v] (null; setpath($p; $v))
| walk(if type == "array"
then map(select(. != null) | if . == ":null:" then null else . end)
else . end)
Upvotes: 2