假设我有以下 JSON 文件:
[
{
"name1": "fruits",
"name2": "cars",
"name3": "houses"
}
]
我知道我可以用于jq
重命名其值,如下所示:
jq '[.[] | .["newname1"] = .name1 | del(.name1)]' file
这工作正常,它允许我甚至在更复杂的 JSON 结构上进行更改...但是,这是我想要更改的键的非常明确的声明。执行相同操作的另一种方法是使用以下命令:
jq 'map(with_entries(if .key == "name1" then .key = "newname1" else . end))' file
这是一种检查 JSON(对象数组)内具有特定名称的所有键并更改它们的方法。key
在这种情况下,我不需要显式声明 的名称。但是,这仅适用于对象数组。我想找到一种以递归方式更改 json 内所有键的方法。假设我有一个如下所示的 JSON:
{
"name1": "one",
"type": "FeatureCollection",
"features": [
{
"name1": "one",
"valueA": "0",
"valueB": "0",
"keyB": "2",
"keyC": "3"
},
{
"name1": "two",
"valueA": "11",
"valueB": "21",
"keyB": "15",
"keyC": "20"
}
]
}
我的最后一条jq
命令不适用于此 JSON。有没有办法name1
使用递归更改所有键jq
?也许找到一种recurse(.[]?;true)
与该命令一起使用的方法?是否可以?
答案1
jq 'walk(if type == "object" then with_entries( if .key == "name1" then .key = "newname1" else . end ) else . end)' file
这或多或少直接来自jq
手册(描述功能的部分walk()
)。该walk()
函数的行为类似于“递归map()
”,我们唯一需要注意的是检查我们当前正在处理的实体的类型。
使用walk()
,您还可以应用您的第一种方法:
jq 'walk(if type == "object" and has("name1") then ( .newname1 = .name1 | del(.name1) ) else . end)' file
然而,这确实将newname1
密钥放在每个对象的最后,而不是替换name1
到找到它的位置(如果这很重要)。
另一种方法(jq
1.6)是使用递归体面运算符..
,选择具有我们正在寻找的密钥的任何对象,然后更新这些对象:
jq '(.. | select(has("name1")?)) |= with_entries(if .key == "name1" then .key = "newname1" else . end)' file