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

関連情報