我有一个嵌套的JSON对象,每个级别都有相同的属性键,每个级别的区别是一个名为name的属性。如果我想向下遍历到具有特定的name属性“路径”的级别,我将如何构造jq过滤器?
下面是一些表示文件系统目录结构的示例JSON数据:
{
"subs": [
{
"name": "aaa",
"subs": [
{
"name": "bbb",
"subs": [
{
"name": "ccc",
"subs": [
{
"name": "ddd",
"payload": "xyz"
}
]
}
]
}
]
}
]
}什么是用于获取“路径”aaa/bbb/ccc/ddd中有效载荷值的jq过滤器?
先前的研究:
name的对象。但是,执行的递归基于一组特定的已知属性名("values[].links.clone[]")。在我的例子中,我的等价物就是"subs[].subs[].subs[]“。发布于 2017-05-12 21:38:04
以下是通用解决方案的基础:
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"] ) | .payloadTCO
上面对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 )发布于 2017-05-12 20:36:07
以下jq命令中的筛选器递归到具有name属性的对象的“路径”,这些对象对应于“路径”aaa/bbb/ccc/ddd:
jq '.subs[] | select(.name = "aaa") | .subs[] | select(.name = "bbb") | .subs[] | select(.name = "ccc") | .subs[] | .payload'这里是在qplay.org上直播的:
https://stackoverflow.com/questions/43946092
复制相似问题