如何根据JQ中的路径列表过滤掉JSON
How to filter out a JSON based on list of paths in JQ
给定一个任意JSON输入:
{
"id":"038020",
"title":"Teenage Mutant Ninja Turtles: Out of the Shadows",
"turtles":[
{
"name":"Leonardo",
"mask":"blue"
},
{
"name":"Michelangelo",
"mask":"orange"
},
{
"name":"Donatello",
"mask":"purple"
},
{
"name":"Raphael",
"mask":"red"
}
],
"summary":"The Turtles continue to live in the shadows and no one knows they were the ones who took down Shredder",
"cast":"Megan Fox, Will Arnett, Tyler Perry",
"director":"Dave Green"
}
以及任意 JQ 路径列表,如[".turtles[].name", ".cast", ".does.not.exist"]
,或任何类似格式
如何仅使用列表路径中包含的信息创建新的 JSON?
在这种情况下,预期结果将是:
{
"turtles":[
{
"name":"Leonardo"
},
{
"name":"Michelangelo"
},
{
"name":"Donatello"
},
{
"name":"Raphael"
}
],
"cast":"Megan Fox, Will Arnett, Tyler Perry"
}
我在类似 "removing null
entries" from a JSON using the walk function present in jq1.5+ 的问题中看到过类似的解决方案,有点类似于:
def filter_list(input, list):
input
| walk(
if type == "object" then
with_entries( select(.key | IN( list )))
else
.
end);
filter_list([.], [.a, .b, .c[].d])
但它应该以某种方式考虑 JSON 中的完整路径。
解决这个问题的最佳方法是什么?
如果 $paths 包含显式 jq 路径数组(例如 [ ["turtles", 0, "name"], ["cast"]])
,最简单的方法是
使用以下过滤器:
. as $in
| reduce $paths[] as $p (null; setpath($p; $in | getpath($p)))
扩展路径表达式
为了能够处理扩展路径表达式,例如 ["turtles"、[]、"name"],其中 []
旨在覆盖 turtles
数组,我们定义如下辅助函数:
def xpath($ary):
. as $in
| if ($ary|length) == 0 then null
else $ary[0] as $k
| if $k == []
then range(0;length) as $i | $in[$i] | xpath($ary[1:]) | [$i] + .
else .[$k] | xpath($ary[1:]) | [$k] + .
end
end ;
为了说明方便,我们再定义一下:
def paths($ary): $ary[] as $path | xpath($path);
然后根据给定的输入,表达式:
. as $in
| reduce paths([ ["turtles", [], "name"], ["cast"]]) as $p
(null; setpath($p; $in | getpath($p)) )
产生如下所示的输出。
使用path
值得指出的是,处理“.turtles[].name”等表达式的一种方法是使用内置过滤器 path/1
.
例如:
# Emit a stream of paths:
def paths: path(.turtles[].name), ["cast"];
. as $in
| reduce paths as $p (null; setpath($p; $in | getpath($p)))
输出:
{
"turtles": [
{
"name": "Leonardo"
},
{
"name": "Michelangelo"
},
{
"name": "Donatello"
},
{
"name": "Raphael"
}
],
"cast": "Megan Fox, Will Arnett, Tyler Perry"
}
给定一个任意JSON输入:
{
"id":"038020",
"title":"Teenage Mutant Ninja Turtles: Out of the Shadows",
"turtles":[
{
"name":"Leonardo",
"mask":"blue"
},
{
"name":"Michelangelo",
"mask":"orange"
},
{
"name":"Donatello",
"mask":"purple"
},
{
"name":"Raphael",
"mask":"red"
}
],
"summary":"The Turtles continue to live in the shadows and no one knows they were the ones who took down Shredder",
"cast":"Megan Fox, Will Arnett, Tyler Perry",
"director":"Dave Green"
}
以及任意 JQ 路径列表,如[".turtles[].name", ".cast", ".does.not.exist"]
,或任何类似格式
如何仅使用列表路径中包含的信息创建新的 JSON? 在这种情况下,预期结果将是:
{
"turtles":[
{
"name":"Leonardo"
},
{
"name":"Michelangelo"
},
{
"name":"Donatello"
},
{
"name":"Raphael"
}
],
"cast":"Megan Fox, Will Arnett, Tyler Perry"
}
我在类似 "removing null
entries" from a JSON using the walk function present in jq1.5+ 的问题中看到过类似的解决方案,有点类似于:
def filter_list(input, list):
input
| walk(
if type == "object" then
with_entries( select(.key | IN( list )))
else
.
end);
filter_list([.], [.a, .b, .c[].d])
但它应该以某种方式考虑 JSON 中的完整路径。
解决这个问题的最佳方法是什么?
如果 $paths 包含显式 jq 路径数组(例如 [ ["turtles", 0, "name"], ["cast"]])
,最简单的方法是
使用以下过滤器:
. as $in
| reduce $paths[] as $p (null; setpath($p; $in | getpath($p)))
扩展路径表达式
为了能够处理扩展路径表达式,例如 ["turtles"、[]、"name"],其中 []
旨在覆盖 turtles
数组,我们定义如下辅助函数:
def xpath($ary):
. as $in
| if ($ary|length) == 0 then null
else $ary[0] as $k
| if $k == []
then range(0;length) as $i | $in[$i] | xpath($ary[1:]) | [$i] + .
else .[$k] | xpath($ary[1:]) | [$k] + .
end
end ;
为了说明方便,我们再定义一下:
def paths($ary): $ary[] as $path | xpath($path);
然后根据给定的输入,表达式:
. as $in
| reduce paths([ ["turtles", [], "name"], ["cast"]]) as $p
(null; setpath($p; $in | getpath($p)) )
产生如下所示的输出。
使用path
值得指出的是,处理“.turtles[].name”等表达式的一种方法是使用内置过滤器 path/1
.
例如:
# Emit a stream of paths:
def paths: path(.turtles[].name), ["cast"];
. as $in
| reduce paths as $p (null; setpath($p; $in | getpath($p)))
输出:
{
"turtles": [
{
"name": "Leonardo"
},
{
"name": "Michelangelo"
},
{
"name": "Donatello"
},
{
"name": "Raphael"
}
],
"cast": "Megan Fox, Will Arnett, Tyler Perry"
}