
Nehmen wir an, ich habe die folgende JSON-Datei:
[
{
"name1": "fruits",
"name2": "cars",
"name3": "houses"
}
]
jq
Ich 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. key
In 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 jq
Befehl funktioniert bei diesem JSON nicht. Gibt es eine Möglichkeit, alle name1
Schlüssel rekursiv zu ändern, indem man verwendet ? Vielleicht gibt es eine Möglichkeit, zusammen mit diesem Befehl jq
zu 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 jq
Handbuch (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 newname1
Schlüssel jedoch in jedem Objekt ans Ende gesetzt, anstatt ihn name1
an der Position zu ersetzen, an der er gefunden wurde (falls das wichtig ist).
Ein anderer Ansatz (mit jq
1.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