如何在每个对象都有Name属性的嵌套JSON上使用JQ递归? [英] How to recurse with jq on nested JSON where each object has a name property?
本文介绍了如何在每个对象都有Name属性的嵌套JSON上使用JQ递归?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我有一个嵌套的JSON对象,其中每个级别都有相同的属性键,每个级别的区别是一个名为name
的属性。如果我要向下遍历到具有name
属性的特定"路径"的级别,我应该如何制定jq
过滤?
以下是表示文件系统目录结构的一些示例JSON数据:
{
"subs": [
{
"name": "aaa",
"subs": [
{
"name": "bbb",
"subs": [
{
"name": "ccc",
"subs": [
{
"name": "ddd",
"payload": "xyz"
}
]
}
]
}
]
}
]
}
获取路径aaa/bbb/ccc/ddd中负载的值的jq
过滤是什么?
以前的研究:
jq - select objects with given key name-有帮助,但在JSON中查找包含指定名称的任何元素,而我查找的是嵌套在一组也具有特定名称的对象下的元素。
http://arjanvandergaag.nl/blog/wrestling-json-with-jq.html-在第4节中很有帮助,其中显示了如何提取具有特定值的属性
name
的对象。但是,执行的递归基于一组特定的已知属性名称("Values[].links.clone[]")。在我的例子中,我的等价物只是"subs[].Subs[].Subs[]"。
推荐答案
以下是通用解决方案的基础:
def descend(name): .subs[] | select(.name == name);
因此您的特定查询可以表示为:
descend( "aaa") | descend( "bbb") | descend( "ccc") | descend( "ddd") | .payload
或稍好一些,仍使用上述descend
的定义:
def path(array):
if (array|length)==0 then .
else descend(array[0]) | path(array[1:])
end;
path( ["aaa", "bbb", "ccc", "ddd"] ) | .payload
总拥有成本
上述path/1
的递归定义非常简单,但不适合嵌套非常深的数据结构,例如深度大于1000的数据结构。下面是另一个定义,它利用了JQ的尾部调用优化,因此运行速度非常快:
def atpath(array):
[array, .]
| until( .[0] == []; .[0] as $a | .[1] | descend($a[0]) | [$a[1:], . ] )
| .[1];
.aaa.bbb.ccc.ddd
如果您希望能够使用.aaa.bbb.ccc.ddd表示法,一种方法是从"展平"数据开始:
def flat:
{ (.name): (if .subs then (.subs[] | flat) else .payload end) };
由于顶级元素没有"name"标记,因此查询将为:
.subs[] | flat | .aaa.bbb.ccc.ddd
这里有一个更有效的方法,再次使用上面定义的descend
:
def payload(p):
def get($array):
if $array == []
then .payload
else descend($array[0]) | get($array[1:]) end;
get( null | path(p) );
payload( .aaa.bbb.ccc.ddd )
这篇关于如何在每个对象都有Name属性的嵌套JSON上使用JQ递归?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文