jq select 可以通过过滤器同时保留完整的输入上下文吗?
Can jq select via a filter while retaining the full input context?
在 jq 中是否有通用机制 select JSON 文件的任意元素,但 return 这些元素的完整结构上下文?例如,如果我有以下内容:
{
"foo": {
"one": true,
"two": false,
"three": {
"hello": "world"
},
"four": true
},
"bar": [
1,
4,
5
],
"baz": true
}
使用过滤器 .foo,.baz
通常会导致:
{
"one": true,
"two": false,
"three": {
"hello": "world"
},
"four": true
}
true
但我想要的是:
{
"foo": {
"one": true,
"two": false,
"three": {
"hello": "world"
},
"four": true
},
"baz": true
}
我可以使用 select
专门为给定的过滤器解决这个问题,但我想要一些通用的东西,以便能够 运行 相同的代码与不同的过滤器并获得相同的类型结果,例如运行 过滤器 .foo.three,.bar[1]
将导致:
{
"foo": {
"three": {
"hello": "world"
}
},
"bar": [
4
]
}
谢谢!
充其量您可以直接通过在 {..}
下命名键名来构建对象,然后应用进一步的转换以仅获取所需的路径
{foo, bar} | .foo |= {three} | .bar |= [.[1]]
您可以将查询转换为路径,将输入转换为流,select 匹配查询路径的部分,并将其重建为单个输出:
def extract(f):
reduce (
path(f) as $path | tostream
| select(length > 1 and (.[0] | index($path) == 0))
) as $set (
null;
setpath($set[0]; $set[1])
);
使用 .foo
和 .baz
的第一个示例:
jq 'def extract(f): …; extract(.foo, .baz)'
{
"foo": {
"one": true,
"two": false,
"three": {
"hello": "world"
},
"four": true
},
"baz": true
}
虽然与稀疏数组一样,它会用 null
填充缺失的项目,否则索引将不再匹配。使用 .foo.three
和 .bar[1]
的第二个示例:
jq 'def extract(f): …; extract(.foo.three, .bar[1])'
{
"foo": {
"three": {
"hello": "world"
}
},
"bar": [
null,
4
]
}
这将给出您想要的 .foo.three,.bar[1]
的结果:
jq 'def extract(f):
. as $input |
reduce path(f) as $path (
null;
if ($path | last | type) == "string"
then setpath($path; $input | getpath($path))
else setpath(($path|.[:-1]);
getpath($path|.[:-1]) +
[$input | getpath($path)]
)
end
);
extract(.foo.three, .bar[1])' data.json
在 jq 中是否有通用机制 select JSON 文件的任意元素,但 return 这些元素的完整结构上下文?例如,如果我有以下内容:
{
"foo": {
"one": true,
"two": false,
"three": {
"hello": "world"
},
"four": true
},
"bar": [
1,
4,
5
],
"baz": true
}
使用过滤器 .foo,.baz
通常会导致:
{
"one": true,
"two": false,
"three": {
"hello": "world"
},
"four": true
}
true
但我想要的是:
{
"foo": {
"one": true,
"two": false,
"three": {
"hello": "world"
},
"four": true
},
"baz": true
}
我可以使用 select
专门为给定的过滤器解决这个问题,但我想要一些通用的东西,以便能够 运行 相同的代码与不同的过滤器并获得相同的类型结果,例如运行 过滤器 .foo.three,.bar[1]
将导致:
{
"foo": {
"three": {
"hello": "world"
}
},
"bar": [
4
]
}
谢谢!
充其量您可以直接通过在 {..}
下命名键名来构建对象,然后应用进一步的转换以仅获取所需的路径
{foo, bar} | .foo |= {three} | .bar |= [.[1]]
您可以将查询转换为路径,将输入转换为流,select 匹配查询路径的部分,并将其重建为单个输出:
def extract(f):
reduce (
path(f) as $path | tostream
| select(length > 1 and (.[0] | index($path) == 0))
) as $set (
null;
setpath($set[0]; $set[1])
);
使用 .foo
和 .baz
的第一个示例:
jq 'def extract(f): …; extract(.foo, .baz)'
{
"foo": {
"one": true,
"two": false,
"three": {
"hello": "world"
},
"four": true
},
"baz": true
}
虽然与稀疏数组一样,它会用 null
填充缺失的项目,否则索引将不再匹配。使用 .foo.three
和 .bar[1]
的第二个示例:
jq 'def extract(f): …; extract(.foo.three, .bar[1])'
{
"foo": {
"three": {
"hello": "world"
}
},
"bar": [
null,
4
]
}
这将给出您想要的 .foo.three,.bar[1]
的结果:
jq 'def extract(f):
. as $input |
reduce path(f) as $path (
null;
if ($path | last | type) == "string"
then setpath($path; $input | getpath($path))
else setpath(($path|.[:-1]);
getpath($path|.[:-1]) +
[$input | getpath($path)]
)
end
);
extract(.foo.three, .bar[1])' data.json