[英]Can jq handle nested JSON data?
Maybe this is too much of a stretch for 'jq' and I need to jump into the python json module, but let's throw down a challenge for the gurus!! 也许这对于'jq'来说太过分了,我需要跳入python json模块,但是让我们为大师们挑战一下吧!
I have some JSON data (from the i3 window manager) that looks a bit like this (simplified). 我有一些JSON数据(来自i3窗口管理器),看起来有点像这样(简化)。 I want to dig down through an arbitrary number of levels of .nodes/.floating_nodes and pull out .nodes or .floating_nodes that have "window" set to non-null.
我想深入挖掘任意数量的.nodes / .floating_nodes级别,并拉出将“ window”设置为非null的.nodes或.floating_nodes。 :
:
{
"floating_nodes": [],
"nodes": [
{
"floating_nodes": [],
"nodes": [
{
"floating_nodes": [],
"nodes": [
{
"floating_nodes": [],
"nodes": [],
"window": null,
"name": "__i3_scratch",
}
],
"window": null,
"name": "foobar",
}
],
"window": null,
"name": "__i3",
},
{
"floating_nodes": [],
"nodes": [
{
"floating_nodes": [],
"nodes": [],
"window": null,
"name": "topdock",
},
{
"floating_nodes": [],
"nodes": [
{
"floating_nodes": [],
"nodes": [
{
"floating_nodes": [],
"nodes": [],
"window": 8388613,
"name": "16:11 bhepple:.../~ — Konsole",
"rect": {
"height": 1061,
"width": 1920,
"y": 0,
"x": 0
},
],
"window": null,
"name": "1",
}
],
"window": null,
"name": "content",
},
{
"floating_nodes": [],
"nodes": [
{
"floating_nodes": [],
"nodes": [],
"window": 14680070,
"name": "i3bar for output VNC-0",
}
],
"window": null,
"name": "bottomdock",
}
],
"window": null,
"name": "VNC-0",
}
],
"window": null,
"name": "root",
}
My sample JSON was a bit broken by my simplifications so here's the full version: 我的示例JSON被我的简化打断了,所以这是完整版本:
{"id":10883136,"type":"root","orientation":"horizontal","scratchpad_state":"none","percent":null,"urgent":false,"focused":false,"layout":"splith","workspace_layout":"default","last_split_layout":"splith","border":"pixel","current_border_width":-1,"rect":{"x":0,"y":0,"width":1920,"height":1080},"deco_rect":{"x":0,"y":0,"width":0,"height":0},"window_rect":{"x":0,"y":0,"width":0,"height":0},"geometry":{"x":0,"y":0,"width":0,"height":0},"name":"root","window":null,"nodes":[{"id":10883568,"type":"output","orientation":"none","scratchpad_state":"none","percent":0.5,"urgent":false,"focused":false,"layout":"output","workspace_layout":"default","last_split_layout":"splith","border":"pixel","current_border_width":-1,"rect":{"x":0,"y":0,"width":1920,"height":1080},"deco_rect":{"x":0,"y":0,"width":0,"height":0},"window_rect":{"x":0,"y":0,"width":0,"height":0},"geometry":{"x":0,"y":0,"width":0,"height":0},"name":"__i3","window":null,"nodes":[{"id":10884128,"type":"con","orientation":"horizontal","scratchpad_state":"none","percent":null,"urgent":false,"focused":false,"layout":"splith","workspace_layout":"default","last_split_layout":"splith","border":"pixel","current_border_width":-1,"rect":{"x":0,"y":0,"width":0,"height":0},"deco_rect":{"x":0,"y":0,"width":0,"height":0},"window_rect":{"x":0,"y":0,"width":0,"height":0},"geometry":{"x":0,"y":0,"width":0,"height":0},"name":"content","window":null,"nodes":[{"id":10884720,"type":"workspace","orientation":"none","scratchpad_state":"none","percent":null,"urgent":false,"focused":false,"layout":"splith","workspace_layout":"default","last_split_layout":"splith","border":"pixel","current_border_width":-1,"rect":{"x":0,"y":0,"width":0,"height":0},"deco_rect":{"x":0,"y":0,"width":0,"height":0},"window_rect":{"x":0,"y":0,"width":0,"height":0},"geometry":{"x":0,"y":0,"width":0,"height":0},"name":"__i3_scratch","num":-1,"window":null,"nodes":[],"floating_nodes":[],"focus":[],"fullscreen_mode":1,"sticky":false,"floating":"auto_off","swallows":[]}],"floating_nodes":[],"focus":[10884720],"fullscreen_mode":0,"sticky":false,"floating":"auto_off","swallows":[]}],"floating_nodes":[],"focus":[10884128],"fullscreen_mode":0,"sticky":false,"floating":"auto_off","swallows":[]},{"id":10886256,"type":"output","orientation":"none","scratchpad_state":"none","percent":0.5,"urgent":false,"focused":false,"layout":"output","workspace_layout":"default","last_split_layout":"splith","border":"pixel","current_border_width":-1,"rect":{"x":0,"y":0,"width":1920,"height":1080},"deco_rect":{"x":0,"y":0,"width":0,"height":0},"window_rect":{"x":0,"y":0,"width":0,"height":0},"geometry":{"x":0,"y":0,"width":0,"height":0},"name":"VNC-0","window":null,"nodes":[{"id":10886944,"type":"dockarea","orientation":"none","scratchpad_state":"none","percent":null,"urgent":false,"focused":false,"layout":"dockarea","workspace_layout":"default","last_split_layout":"splith","border":"pixel","current_border_width":-1,"rect":{"x":0,"y":0,"width":1920,"height":0},"deco_rect":{"x":0,"y":0,"width":0,"height":0},"window_rect":{"x":0,"y":0,"width":0,"height":0},"geometry":{"x":0,"y":0,"width":0,"height":0},"name":"topdock","window":null,"nodes":[],"floating_nodes":[],"focus":[],"fullscreen_mode":0,"sticky":false,"floating":"auto_off","swallows":[{"dock":2,"insert_where":2}]},{"id":10887648,"type":"con","orientation":"horizontal","scratchpad_state":"none","percent":null,"urgent":false,"focused":false,"layout":"splith","workspace_layout":"default","last_split_layout":"splith","border":"pixel","current_border_width":-1,"rect":{"x":0,"y":0,"width":1920,"height":1061},"deco_rect":{"x":0,"y":0,"width":0,"height":0},"window_rect":{"x":0,"y":0,"width":0,"height":0},"geometry":{"x":0,"y":0,"width":0,"height":0},"name":"content","window":null,"nodes":[{"id":10889056,"type":"workspace","orientation":"horizontal","scratchpad_state":"none","percent":null,"urgent":false,"focused":false,"layout":"splith","workspace_layout":"default","last_split_layout":"splith","border":"pixel","current_border_width":-1,"rect":{"x":0,"y":0,"width":1920,"height":1061},"deco_rect":{"x":0,"y":0,"width":0,"height":0},"window_rect":{"x":0,"y":0,"width":0,"height":0},"geometry":{"x":0,"y":0,"width":0,"height":0},"name":"1","num":1,"window":null,"nodes":[{"id":10895664,"type":"con","orientation":"none","scratchpad_state":"none","percent":1.0,"urgent":false,"focused":true,"layout":"splith","workspace_layout":"default","last_split_layout":"splith","border":"pixel","current_border_width":1,"rect":{"x":0,"y":0,"width":1920,"height":1061},"deco_rect":{"x":0,"y":0,"width":0,"height":0},"window_rect":{"x":1,"y":1,"width":1918,"height":1059},"geometry":{"x":0,"y":0,"width":958,"height":1059},"name":"16:11 bhepple:.../~ — Konsole","window":8388613,"window_properties":{"class":"konsole","instance":"konsole","title":"16:11 bhepple:.../~ — Konsole","transient_for":null},"nodes":[],"floating_nodes":[],"focus":[],"fullscreen_mode":0,"sticky":false,"floating":"auto_off","swallows":[]}],"floating_nodes":[],"focus":[10895664],"fullscreen_mode":1,"sticky":false,"floating":"auto_off","swallows":[]}],"floating_nodes":[],"focus":[10889056],"fullscreen_mode":0,"sticky":false,"floating":"auto_off","swallows":[]},{"id":10888352,"type":"dockarea","orientation":"none","scratchpad_state":"none","percent":null,"urgent":false,"focused":false,"layout":"dockarea","workspace_layout":"default","last_split_layout":"splith","border":"pixel","current_border_width":-1,"rect":{"x":0,"y":1061,"width":1920,"height":19},"deco_rect":{"x":0,"y":0,"width":0,"height":0},"window_rect":{"x":0,"y":0,"width":0,"height":0},"geometry":{"x":0,"y":0,"width":0,"height":0},"name":"bottomdock","window":null,"nodes":[{"id":10891392,"type":"con","orientation":"none","scratchpad_state":"none","percent":1.0,"urgent":false,"focused":false,"layout":"splith","workspace_layout":"default","last_split_layout":"splith","border":"pixel","current_border_width":1,"rect":{"x":0,"y":1061,"width":1920,"height":19},"deco_rect":{"x":0,"y":0,"width":0,"height":0},"window_rect":{"x":0,"y":0,"width":1920,"height":19},"geometry":{"x":0,"y":1061,"width":3840,"height":19},"name":"i3bar for output VNC-0","window":14680070,"window_properties":{"class":"i3bar","instance":"i3bar","title":"i3bar for output VNC-0","transient_for":null},"nodes":[],"floating_nodes":[],"focus":[],"fullscreen_mode":0,"sticky":false,"floating":"auto_off","swallows":[]}],"floating_nodes":[],"focus":[10891392],"fullscreen_mode":0,"sticky":false,"floating":"auto_off","swallows":[{"dock":3,"insert_where":2}]}],"floating_nodes":[],"focus":[10887648,10886944,10888352],"fullscreen_mode":0,"sticky":false,"floating":"auto_off","swallows":[]}],"floating_nodes":[],"focus":[10886256,10883568],"fullscreen_mode":0,"sticky":false,"floating":"auto_off","swallows":[]}
Sure, jq can do this! 当然,jq可以做到这一点!
First, we use the recurse operator, ..
, to recursively iterate through everything. 首先,我们使用递归运算符
..
,对所有内容进行递归迭代。 Then, we get all the .nodes
and .floating_nodes
, and we use ?
然后,获得所有的
.nodes
和.floating_nodes
,并使用?
to ignore errors that would arise from trying to get properties from numbers, strings or objects. 忽略尝试从数字,字符串或对象中获取属性而产生的错误。 Then, we get all the elements in these arrays with
[]
. 然后,使用
[]
获得这些数组中的所有元素。 Again, ignoring the errors in the previous step left some null
s, so we ignore the errors from trying to use []
on null
s with a ?
再次,忽略在上一步中的错误留下一些
null
S,所以我们试图使用忽略错误[]
对null
,以及符合S ?
. 。 Lastly, we pipe everything to
select(.window != null)
, and we wrap every result in an array for easier treatment. 最后,我们将所有内容通过管道传递给
select(.window != null)
,并将每个结果包装在数组中以便于处理。
jq '[.. | .floating_nodes?, .nodes? | .[]? | select(.window != null)]'
如果window
属性只能出现在node
或floating_node
对象上,则可以通过仅搜索具有window
属性的所有对象来简化操作。
.. | objects | select(.window != null)
Working off Santiago's solution and trying to backfill for what may be lacking in jq-1.3 I got this to work: 解决圣地亚哥的解决方案,并尝试回填jq-1.3中可能缺少的内容,我可以这样做:
jq 'recurse(.[]) | .floating_nodes, .nodes | .[] | select(.window != null) | select(.focused == true) | .name'
... it also gave lots of error messages such as: ...它还给出了许多错误消息,例如:
jq: error: Cannot iterate over number
jq: error: Cannot iterate over null
jq: error: Cannot iterate over null
jq: error: Cannot index number with string
The following has been tested with jq 1.3, 1.4, and 1.5: 以下已通过jq 1.3、1.4和1.5进行了测试:
recurse(if type == "object" or type == "array" then .[] else empty end)
| select(type == "object")
| ( select(.nodes|type == "array") | .nodes[]),
( select(.floating_nodes|type == "array") | .floating_nodes[])
| select( .window != null )
Using the "full version" of the given input, jq 1.3 produces the following output: 使用给定输入的“完整版本”,jq 1.3产生以下输出:
{
"swallows": [],
"floating": "auto_off",
"sticky": false,
"fullscreen_mode": 0,
"focus": [],
"floating_nodes": [],
"nodes": [],
"window_properties": {
"transient_for": null,
"title": "16:11 bhepple:.../~ — Konsole",
"instance": "konsole",
"class": "konsole"
},
"window": 8388613,
"name": "16:11 bhepple:.../~ — Konsole",
"layout": "splith",
"focused": true,
"urgent": false,
"percent": 1,
"scratchpad_state": "none",
"orientation": "none",
"type": "con",
"id": 10895664,
"workspace_layout": "default",
"last_split_layout": "splith",
"border": "pixel",
"current_border_width": 1,
"rect": {
"height": 1061,
"width": 1920,
"y": 0,
"x": 0
},
"deco_rect": {
"height": 0,
"width": 0,
"y": 0,
"x": 0
},
"window_rect": {
"height": 1059,
"width": 1918,
"y": 1,
"x": 1
},
"geometry": {
"height": 1059,
"width": 958,
"y": 0,
"x": 0
}
}
{
"swallows": [],
"floating": "auto_off",
"sticky": false,
"fullscreen_mode": 0,
"focus": [],
"floating_nodes": [],
"nodes": [],
"window_properties": {
"transient_for": null,
"title": "i3bar for output VNC-0",
"instance": "i3bar",
"class": "i3bar"
},
"window": 14680070,
"name": "i3bar for output VNC-0",
"layout": "splith",
"focused": false,
"urgent": false,
"percent": 1,
"scratchpad_state": "none",
"orientation": "none",
"type": "con",
"id": 10891392,
"workspace_layout": "default",
"last_split_layout": "splith",
"border": "pixel",
"current_border_width": 1,
"rect": {
"height": 19,
"width": 1920,
"y": 1061,
"x": 0
},
"deco_rect": {
"height": 0,
"width": 0,
"y": 0,
"x": 0
},
"window_rect": {
"height": 19,
"width": 1920,
"y": 0,
"x": 0
},
"geometry": {
"height": 19,
"width": 3840,
"y": 1061,
"x": 0
}
}
Here is a solution which uses tostream to scan a stream of [path,value] arrays from the given input. 这是一个使用tostream扫描来自给定输入的[path,value]数组流的解决方案。 It then uses select to pick out only paths ending in "window" and whose corresponding value is not null.
然后,它使用select来选择仅以“ window”结尾且其对应值不为null的路径。 Finally it uses foreach and getpath to produce a stream of the containing objects.
最后,它使用foreach和getpath生成包含对象的流。
foreach ( tostream
| select(length == 2 and .[0][-1] == "window" and .[1] != null)
) as $p (
.
; .
; getpath($p[0][:-1])
)
EDIT: I now realize a filter of the form foreach E as $X (.; .; R)
can almost always be rewritten as E as $X | R
编辑:我现在意识到形式为
foreach E as $X (.; .; R)
的过滤器foreach E as $X (.; .; R)
几乎总是可以重写为E as $X | R
E as $X | R
so the above is really just E as $X | R
所以上面真的是
( tostream | select(length == 2 and .[0][-1] == "window" and .[1] != null) ) as $p
| getpath($p[0][:-1])
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.