Ist es möglich, mit jq Schlüsselnamen mithilfe der Methode with_entries rekursiv zu ändern?

Ist es möglich, mit jq Schlüsselnamen mithilfe der Methode with_entries rekursiv zu ändern?

Nehmen wir an, ich habe die folgende JSON-Datei:

[
  {
    "name1": "fruits",
    "name2": "cars",
    "name3": "houses"
  }
]

jqIch weiß, dass ich die Werte folgendermaßen umbenennen kann :

jq '[.[] | .["newname1"] = .name1 | del(.name1)]' file

Das funktioniert gut und ermöglicht mir, auch an komplexeren JSON-Strukturen Änderungen vorzunehmen... Allerdings ist das eine sehr explizite Deklaration der Schlüssel, die ich ändern möchte. Eine alternative Möglichkeit, dasselbe zu tun, wäre mit dem folgenden Befehl:

jq 'map(with_entries(if .key == "name1" then .key = "newname1" else . end))' file 

Auf diese Weise können alle Schlüssel mit bestimmten Namen in einem JSON, das ein Array von Objekten ist, überprüft und geändert werden. keyIn diesem Fall muss ich den Namen nicht explizit angeben. Dies funktioniert jedoch nur bei einem Array von Objekten. Ich möchte eine Möglichkeit finden, alle Schlüssel in einem solchen JSON rekursiv zu ändern. Nehmen wir an, ich habe ein JSON wie das folgende:

{
  "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"
    }
  ]
}

Mein letzter jqBefehl funktioniert bei diesem JSON nicht. Gibt es eine Möglichkeit, alle name1Schlüssel rekursiv zu ändern, indem man verwendet ? Vielleicht gibt es eine Möglichkeit, zusammen mit diesem Befehl jqzu verwenden ? Ist das möglich?recurse(.[]?;true)

Antwort1

jq 'walk(if type == "object" then with_entries( if .key == "name1" then .key = "newname1" else . end ) else . end)' file

Dies stammt mehr oder weniger direkt aus dem jqHandbuch (der Abschnitt, der die walk()Funktion beschreibt). Die walk()Funktion verhält sich wie eine „rekursive map()“ Funktion und das einzige, worauf wir achten müssen, ist, den Typ der Entität zu überprüfen, mit der wir es gerade zu tun haben.

Mithilfe von walk()können Sie auch Ihren ersten Ansatz anwenden:

jq 'walk(if type == "object" and has("name1") then ( .newname1 = .name1 | del(.name1) ) else . end)' file

Dadurch wird der newname1Schlüssel jedoch in jedem Objekt ans Ende gesetzt, anstatt ihn name1an der Position zu ersetzen, an der er gefunden wurde (falls das wichtig ist).

Ein anderer Ansatz (mit jq1.6) besteht darin, den rekursiven Anständigkeitsoperator zu verwenden .., alles auszuwählen, was den gesuchten Schlüssel hat, und diese Objekte dann zu aktualisieren:

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

verwandte Informationen