是否可以使用 with_entries 方法通过 jq 递归地更改键名称?

是否可以使用 with_entries 方法通过 jq 递归地更改键名称?

假设我有以下 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到找到它的位置(如果这很重要)。

另一种方法(jq1.6)是使用递归体面运算符..,选择具有我们正在寻找的密钥的任何对象,然后更新这些对象:

jq '(.. | select(has("name1")?)) |= with_entries(if .key == "name1" then .key = "newname1" else . end)' file

相关内容