Можно ли рекурсивно изменить имена ключей с помощью jq, используя метод with_entries?

Можно ли рекурсивно изменить имена ключей с помощью jq, используя метод with_entries?

Допустим, у меня есть следующий 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) заключается в использовании рекурсивного оператора Decent .., выбирающего все, что имеет искомый нами ключ, а затем обновляющего эти объекты:

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

Связанный контент