gpt4 book ai didi

json - 如何在每个对象都有一个 name 属性的嵌套 JSON 上使用 jq 进行递归?

转载 作者:行者123 更新时间:2023-12-02 03:55:54 26 4
gpt4 key购买 nike

我有一个嵌套的 JSON 对象,其中每个级别都有相同的属性键,区分每个级别的是一个名为 name 的属性。如果我想向下遍历到具有 name 属性的特定“路径”的级别,我将如何制定 jq 过滤器?

以下是一些表示文件系统目录结构的示例 JSON 数据:

{
"subs": [
{
"name": "aaa",
"subs": [
{
"name": "bbb",
"subs": [
{
"name": "ccc",
"subs": [
{
"name": "ddd",
"payload": "xyz"
}
]
}
]
}
]
}
]
}

用于获取“路径”aaa/bbb/ccc/ddd 中负载值的 jq 过滤器是什么?

先前研究:

  1. jq - select objects with given key name - 很有帮助,但会查找 JSON 中包含指定名称的任何元素,而我正在查找嵌套在一组也具有特定名称的对象下的元素。

  2. 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 )

关于json - 如何在每个对象都有一个 name 属性的嵌套 JSON 上使用 jq 进行递归?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43946092/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com