JSONPath-Syntax-Leitfaden: JSON abfragen und filtern (Beispiele)
JSONPath ist eine Abfragesprache für JSON, so wie XPath eine Abfragesprache für XML ist. Sie schreiben einen Pfadausdruck, und der Auswerter liefert jeden Wert zurück, der passt. Um alle Autorennamen aus einem Bookstore-Dokument zu greifen, schreiben Sie $.store.book[*].author, und Sie bekommen die Liste der Autoren zurück, ohne dafür Traversierungscode zu schreiben.
Dieser Leitfaden führt Sie durch jeden Selektor der JSONPath-Syntax, mit Copy-paste-Beispielen, die Sie beim Lesen ausführen können. Dabei sollten Sie zwei Dialekte unterscheiden. Der Goessner-Dialekt von 2007 ist der De-facto-Klassiker, RFC 9535 ist der formale IETF-Standard, veröffentlicht im Februar 2024. Bei gängigen Pfaden sind sie sich einig, in den Randfällen gehen sie auseinander, und dieser Leitfaden weist auf die Unterschiede hin, sobald sie auftauchen. Jeden Ausdruck unten können Sie im JSONPath Tester ausprobieren und dabei zwischen beiden Engines umschalten, um sie zu vergleichen.
Der folgende Selektor-Spickzettel gibt den Überblick. Der Rest des Artikels entfaltet jede Zeile mit einem ausgearbeiteten Beispiel anhand eines gemeinsamen JSON-Dokuments.
| Selektor | Bedeutung | Beispiel |
|---|---|---|
$ | Wurzel des Dokuments | $ |
@ | Aktuelles Element (in Filtern) | [?(@.price < 10)] |
.name / ['name'] | Untergeordnetes Mitglied | $.store.book |
.. | Rekursiver Abstieg | $..author |
* | Alle Elemente / Mitglieder | $.store.book[*] |
[0] | Array-Index | $.store.book[0] |
[start:end:step] | Array-Slice (halboffen) | $.store.book[0:2] |
[a,b] | Union von Namen / Indizes | $.store.book[0,2] |
[?()] | Filterausdruck | $.store.book[?(@.price < 10)] |
length() count() match() search() value() | RFC 9535-Funktionen (nur im Filter) | [?length(@.title) > 15] |
Was ist JSONPath?
JSONPath ist eine deklarative Abfragesprache, um Knoten aus einem JSON-Dokument auszuwählen. Statt eine Schleife zu schreiben, die Objekte und Arrays durchläuft, beschreiben Sie mit einem Pfad die gewünschte Stelle, und der Auswerter liefert die passenden Werte zurück. Das gedankliche Modell ist dasselbe, das XPath Ihnen für XML gibt: ein Pfad aus Selektoren, die durch die Struktur schreiten.
Es taucht überall auf, wo Entwickler mit JSON arbeiten. Sie nutzen es, um ein Feld aus einer API-Antwort zu ziehen, um in einem Integrationstest einen Wert zu prüfen, um Felder in Pipeline-Konfigurationen für Kubernetes, AWS Step Functions und Azure Logic Apps anzusprechen, und um Daten aus großen oder unregelmäßigen JSON-Dokumenten zu extrahieren, ohne die Traversierungslogik von Hand zu schreiben.
Die Geschichte erklärt, warum sich die Dialekte spalten. Stefan Goessner schlug JSONPath 2007 vor. Es verbreitete sich schnell und wurde zum De-facto-Standard, war aber nie formal spezifiziert, sodass die Implementierungen in den Details auseinanderdrifteten. Die IETF schloss diese Lücke im Februar 2024 mit RFC 9535, der ersten formalen JSONPath-Spezifikation. Beide Dialekte sind heute in Gebrauch, und genau deshalb kann sich derselbe Ausdruck je nach ausführender Bibliothek unterschiedlich verhalten.
Bevor Sie mit dem Abfragen beginnen, hilft es, die Struktur zu lesen. Formatieren Sie unübersichtliche Eingaben mit dem JSON-Formatierer, damit die Verschachtelung sichtbar wird.
Das Beispieldokument
Jedes Beispiel unten läuft gegen das klassische Goessner-Bookstore-JSON. Fügen Sie es einmal ein und verwenden Sie es immer wieder:
{
"store": {
"book": [
{ "title": "Sayings of the Century", "author": "Nigel Rees", "price": 8.95 },
{ "title": "Sword of Honour", "author": "Evelyn Waugh", "price": 12.99 },
{ "title": "Moby Dick", "author": "Herman Melville", "price": 8.99 },
{ "title": "The Lord of the Rings", "author": "J. R. R. Tolkien", "price": 22.99 }
],
"bicycle": { "color": "red", "price": 19.95 }
}
}
Vier Bücher mit Titel, Autor und Preis, dazu ein Fahrrad. Behalten Sie das im Kopf: Die Preise sind 8.95, 12.99, 8.99 und 22.99, und das bestimmt später die Filterergebnisse.
Wurzel, Kind und rekursiver Abstieg ($ . ..)
Jeder Ausdruck beginnt an der Wurzel, geschrieben $. Von dort steigen Sie mit einem Punkt oder mit Klammernotation in untergeordnete Knoten; beide sind gleichwertig:
$.store.book → das Buch-Array
$['store']['book'] → identisches Ergebnis
Klammernotation brauchen Sie, wenn ein Schlüssel Leerzeichen, Punkte oder andere Sonderzeichen enthält: $['first name'] funktioniert dort, wo $.first name versagen würde.
Der Operator .. ist der rekursive Abstieg. Er durchsucht jede Ebene des Dokuments, nicht nur die direkten Kinder, und sammelt alles ein, was dem folgenden Selektor in beliebiger Tiefe entspricht:
$..author
→ ["Nigel Rees", "Evelyn Waugh", "Herman Melville", "J. R. R. Tolkien"]
Wann .. und wann ein vollständiger Pfad
Rekursiver Abstieg ist bequem, aber grob. $..price trifft jeden Preis irgendwo im Baum, einschließlich store.bicycle.price, was Sie womöglich gar nicht wollten. Wenn Sie die Form kennen, schreiben Sie den Pfad aus, damit die Abfrage präzise bleibt:
$..price → [8.95, 12.99, 8.99, 22.99, 19.95] (inklusive Fahrrad)
$.store.book[*].price → [8.95, 12.99, 8.99, 22.99] (nur Bücher)
Heben Sie sich .. für wirklich unregelmäßige oder unbekannte Strukturen auf. Je mehr Sie über Ihre Daten wissen, desto eher sollten Sie einen expliziten Pfad bevorzugen und damit Bequemlichkeit gegen Kontrolle tauschen.
Wildcards, Indizes und Array-Slices (* [0] [start:end:step])
Die Wildcard * wählt alle Elemente eines Arrays oder alle Mitglieder eines Objekts:
$.store.book[*].title
→ ["Sayings of the Century", "Sword of Honour", "Moby Dick", "The Lord of the Rings"]
Array-Indizes sind nullbasiert, und negative Indizes zählen vom Ende:
$.store.book[0].title → ["Sayings of the Century"]
$.store.book[-1].title → ["The Lord of the Rings"]
Slices nutzen dieselbe halboffene [start:end:step]-Konvention wie Python und JavaScript: start ist eingeschlossen, end ist ausgeschlossen.
$.store.book[0:2].title → ["Sayings of the Century", "Sword of Honour"]
Das liefert zwei Bücher zurück, nicht drei: Index 0 und Index 1, mit Stopp vor Index 2. Die ausschließende Endgrenze ist der häufigste JSONPath-Fehler, also lohnt es sich, sie sich fest einzuprägen:
[0:2] → erste ZWEI Elemente (Indizes 0, 1) ← korrekt
[0:3] → erste DREI Elemente (Indizes 0, 1, 2)
Lassen Sie eine Grenze weg, um bis zum Rand zu laufen, und fügen Sie einen Schritt für jedes N-te Element hinzu:
$.store.book[2:].title → ["Moby Dick", "The Lord of the Rings"]
$.store.book[:3].title → erste drei Titel
$.store.book[::2].title → ["Sayings of the Century", "Moby Dick"] (jedes zweite)
Filterausdrücke [?()]
Filter sind der ausdrucksstärkste Teil von JSONPath. Ein Filter [?()] behält nur die Elemente, für die ein Prädikat wahr ist, und innerhalb des Filters bezieht sich @ auf das gerade geprüfte Element.
Um Bücher auszuwählen, die billiger als 10 sind:
$.store.book[?(@.price < 10)].title
→ ["Sayings of the Century", "Moby Dick"]
Gegen die Bookstore-Preise (8.95, 12.99, 8.99, 22.99) qualifizieren sich zwei Bücher. So bauen Sie Filterprädikate Schritt für Schritt auf:
- Gegen ein Literal vergleichen. Verwenden Sie
==,!=,<,<=,>,>=, zum Beispiel@.price > 10. - Eine Zeichenkette abgleichen. Zeichenketten-Literale stehen in einfachen Anführungszeichen:
@.author == 'Nigel Rees'. - Auf Existenz prüfen. Ein bloßer Mitgliedsbezug wählt Elemente aus, die es besitzen:
[?(@.isbn)]behält nur Bücher mit einerisbn. - Bedingungen kombinieren. Verknüpfen Sie Prädikate mit
&&und||:[?(@.price < 10 && @.author == 'Herman Melville')].
Der häufigste Filterfehler ist der Geltungsbereich von @. Innerhalb des Prädikats ist das aktuelle Element @, nicht $. $.price zu schreiben verweist zurück auf die Dokumentwurzel, nicht auf das geprüfte Buch:
$.store.book[?($.price < 10)] → falscher Geltungsbereich, trifft nichts Brauchbares
$.store.book[?(@.price < 10)] → korrekt: der jeweilige Preis jedes Buchs
RFC 9535 vs. Classic in Filtern
Die beiden Dialekte trennen sich bei Leerraum und Anführungszeichen. Classic ist nachsichtig, denn [?(@.price<10)] ohne Leerzeichen lässt sich problemlos parsen. RFC 9535 folgt seiner Grammatik exakt und ist strenger darin, wie der Filter geschrieben wird. Wenn ein Filter, der anderswo funktionierte, scheitert, prüfen Sie die Abstände und die Engine. Halten Sie Filter sauber (Operatoren mit Leerzeichen, Zeichenketten in einfachen Anführungszeichen), und sie werten unabhängig davon, welche Bibliothek sie letztlich ausführt, gleich aus.
Union-Selektoren — mehrere Schlüssel auf einmal auswählen ([a,b])
Ein Union-Selektor listet mehrere Namen oder Indizes innerhalb einer Klammer auf und sammelt sie alle ein:
$.store.book[0]['title','author']
→ ["Sayings of the Century", "Nigel Rees"]
Unions funktionieren auch mit Indizes, und Sie können sie mit anderen Selektoren für eine feste Projektion mischen:
$.store.book[0,2].title → ["Sayings of the Century", "Moby Dick"]
$.store.book[*]['title','price'] → Titel und Preis jedes Buchs
Unions sind das richtige Werkzeug, wenn Sie ein paar bestimmte Felder wollen statt eines ganzen Objekts oder eines Wildcard-Rundumschlags.
RFC 9535-Funktionen: length, count, match, search, value
RFC 9535 definiert fünf Standard-Funktionserweiterungen. Die Regel, über die fast jeder stolpert und die konkurrierende Leitfäden ständig falsch wiedergeben, lautet:
Diese Funktionen sind nur innerhalb eines Filters
[?...]aufrufbar, niemals als eigenständiges Pfadsegment.
$.store.book.length() zu schreiben ist kein gültiges RFC 9535, und die Standardgrammatik weist es zurück. Diese Segment-Aufruf-Form ist eine jsonpath-plus-Erweiterung, nicht Teil der Spezifikation. Um nach Länge zu filtern, rufen Sie die Funktion innerhalb des Prädikats auf:
$.store.book[?length(@.title) > 15]
→ [
{ "title": "Sayings of the Century", "author": "Nigel Rees", "price": 8.95 },
{ "title": "The Lord of the Rings", "author": "J. R. R. Tolkien", "price": 22.99 }
]
Beide ausgewählten Titel sind länger als 15 Zeichen; “Moby Dick” (9) und “Sword of Honour” (15, nicht über 15) sind ausgeschlossen.
Innerhalb eines Filters tut jede Funktion Folgendes:
length()— Länge einer Zeichenkette, eines Arrays oder Objekts:[?length(@.title) > 15]count()— Anzahl der Knoten in einer Knotenliste:[?(count(@.authors) > 1)]match()— Regex-Test auf die ganze Zeichenkette (I-Regexp-Muster):[?match(@.author, 'J.*')]search()— Regex-Test auf Teilzeichenkette:[?search(@.title, 'the')]value()— wandelt eine Einzelknoten-Knotenliste für den Vergleich in ihren Wert um
Alle fünf sind ein RFC 9535-Merkmal. Der Classic-Dialekt (Goessner) implementiert sie nicht. Wenn also ein funktionsbasierter Ausdruck scheitert, vergewissern Sie sich, dass Sie ihn innerhalb eines Filters aufrufen und dass Ihre Engine auf RFC 9535 eingestellt ist.
RFC 9535 vs. Classic Goessner — warum derselbe Ausdruck abweicht
Wenn ein JSONPath-Ausdruck in zwei Werkzeugen unterschiedliche Ergebnisse liefert, ist meist der Dialekt der Grund. So vergleichen sich die beiden:
| Aspekt | Classic Goessner (2007) | RFC 9535 (2024) |
|---|---|---|
| Standardisierung | De facto, nie formalisiert | Erste formale IETF-Spezifikation |
| Filter-Leerraum/-Anführungszeichen | Nachsichtig ([?(@.price<10)] OK) | Streng, folgt der Grammatik exakt |
| Vergleich bei fehlendem Mitglied | Implementierungsabhängig | Wohldefiniert, wirft keinen Fehler |
| Standardfunktionen | Nicht Teil des Dialekts | length count match search value |
| Normalisierte Pfade | Keine kanonische Form | Kanonisch, einfach-anführungszeichige Klammerform |
| Union-Reihenfolge | Variiert je nach Bibliothek | Festgelegt |
Praktischer Rat: Wenn Ihr nachgelagertes System RFC 9535-Konformität bewirbt, schreiben und validieren Sie gegen die Standard-Engine. Wenn Sie einen von jsonpath.com, jsonpath-plus oder einem Jayway-basierten Dienst kopierten Ausdruck pflegen, verwenden Sie Classic, damit sich die Ergebnisse reproduzieren. Der JSONPath Tester lässt beide Engines hinter einem einzigen Umschalter laufen, sodass Sie einen Ausdruck einmal einfügen und Seite an Seite sehen können, wie jeder Dialekt ihn behandelt. Dieser Doppel-Engine-Vergleich macht eine Abweichung schnell sichtbar.
JSONPath vs. XPath vs. jq — was wann verwenden
Diese drei werden gern durcheinandergeworfen, also hier die Kurzfassung:
- JSONPath ist eine deklarative Pfadabfrage für JSON. Sie eignet sich am besten eingebettet in Konfigurationen und Test-Assertions, wo Sie eine Stelle benennen wollen, ohne Code zu schreiben.
- XPath ist das Pendant aus der XML-Welt. JSONPath hat einen Teil seiner Notation übernommen (
*,..,[]), weshalb die Analogie trägt, aber die Sprachen sind nicht austauschbar und die Funktionssätze unterscheiden sich. - jq ist ein Kommandozeilen-JSON-Prozessor. Er geht mit Transformation, Aggregation und Umformung weit über die Pfadauswahl hinaus und lebt in Ihrer Shell-Pipeline.
Die Entscheidung ist meist klar. Für eine eingebettete Assertion oder ein Pipeline-Konfigurationsfeld greifen Sie zu JSONPath. Für shell-gesteuerte Transformation und Datenaufbereitung greifen Sie zu jq; der jq-Spickzettel deckt diesen Arbeitsablauf ausführlich ab. Und wenn die Frage lautet, ob eine Nutzlast einer erwarteten Form entspricht, statt wo ein Feld liegt, validieren Sie sie mit dem JSON Schema Validator und seinem vollständigen Validierungsleitfaden.
7 häufige JSONPath-Fehler
- Wurzel
$vergessen.store.bookwird von den meisten Engines zurückgewiesen; jeder Ausdruck beginnt bei$. - Slice-Off-by-One.
[0:2]sind zwei Elemente, nicht drei, denn die Endgrenze ist ausschließend. - Falscher Dialekt. Einen Classic-Ausdruck unter RFC 9535 (oder umgekehrt) laufen zu lassen, kann einen Parse-Fehler ergeben oder andere Knoten treffen. Stellen Sie die Engine passend um.
- Funktion als eigenständiges Segment.
$.store.book.length()ist ungültiges RFC 9535; rufen Sielength()innerhalb eines Filters auf. @im Filter vergessen.[?($.price < 10)]zeigt auf die Wurzel; verwenden Sie[?(@.price < 10)].- Falsche Klammer-Anführung.
$[store]ist ein Fehler; setzen Sie den Schlüssel in Anführungszeichen:$['store']. - Angenommen,
..stoppe auf der ersten Ebene. Rekursiver Abstieg trifft in jeder Tiefe, nicht nur direkte Kinder.
JSONPath online testen, privat
Die JSONPath-Syntax lernen Sie am schnellsten, indem Sie sie ausführen. Der JSONPath Tester wertet jeden Ausdruck dieses Leitfadens live aus: doppelte RFC 9535- und Classic-Engines, die Ansichten Werte / Pfade / Beide, normalisierte Pfade zum Debuggen und vollständige Ausführung im Browser. Es gibt keinen Upload, keine Anmeldung und kein eval, was den Tester auch für proprietäre Nutzlasten sicher macht. Bauen Sie hier einen Pfad, bestätigen Sie, dass er genau die gewünschten Knoten auswählt, und fügen Sie den validierten Ausdruck dann direkt in Ihren Code, Ihre Tests oder Ihre Pipeline ein.
Für den Rest des JSON-Arbeitsablaufs verwandeln Sie eine Beispielantwort mit JSON to TypeScript in typisierte Interfaces oder vergleichen Sie zwei Dokumente Feld für Feld mit JSON Diff.
Häufig gestellte Fragen
Wofür wird JSONPath verwendet?
JSONPath fragt JSON ohne imperativen Code ab. Entwickler nutzen es, um Felder aus API-Antworten zu ziehen, in Integrationstests Werte zu prüfen und Felder in Konfigurationen für Kubernetes, AWS Step Functions und Azure Logic Apps anzusprechen. Es glänzt beim Extrahieren von Daten aus großen oder unregelmäßigen Strukturen, wo eine von Hand geschriebene Traversierung mühsam wäre.
Was ist der Unterschied zwischen RFC 9535 und klassischem JSONPath?
Classic ist Stefan Goessners De-facto-Dialekt von 2007, weit verbreitet, aber nie formal spezifiziert, weshalb die Bibliotheken auseinanderdrifteten. RFC 9535 ist die formale IETF-Spezifikation vom Februar 2024: Sie definiert eine präzise Grammatik, normalisierte Pfade für Ergebnisse und fünf Standardfunktionen. Die beiden unterscheiden sich an den Rändern bei Filtern, Unions und dem Vergleich fehlender Mitglieder.
Wie funktionieren JSONPath-Filterausdrücke?
Ein Filter [?()] behält nur die Elemente, deren Prädikat wahr ist, und @ ist das aktuelle Element. Zum Beispiel wählt $.store.book[?(@.price < 10)] Bücher mit einem Preis unter 10 aus. Sie können Bedingungen mit && und || kombinieren, prüfen, ob ein Mitglied existiert, und gegen Zeichenketten- oder Zahlenliterale vergleichen.
Kann ich length() als $.store.book.length() verwenden?
Nein. In RFC 9535 sind length() und die anderen vier Funktionen nur innerhalb eines Filters aufrufbar, etwa $.store.book[?length(@.title) > 15]. Die eigenständige Segmentform $.store.book.length() ist eine jsonpath-plus-Erweiterung, kein Standard-JSONPath, und die RFC 9535-Grammatik weist sie zurück.
Ist JSONPath dasselbe wie XPath?
Nein, aber die Idee ist ähnlich. XPath fragt XML ab; JSONPath fragt JSON ab; beide lokalisieren Knoten mit Pfadselektoren. JSONPath hat bewusst einen Teil der XPath-Notation übernommen, etwa *, .. und [], was die Analogie nützlich macht, aber Syntax, Semantik und Funktionssätze sind verschieden und nicht austauschbar.
Was bewirkt der rekursive Abstieg (..) in JSONPath?
Der Operator .. durchsucht jede Ebene des Dokuments, nicht nur die direkten Kinder. $..author sammelt jedes author-Mitglied ein, wo immer es auftaucht, in beliebiger Verschachtelungstiefe. Es ist der schnellste Weg, ein einzelnes Feld aus einer tief verschachtelten oder unregelmäßigen Struktur zu ziehen, aber es kann weit mehr Knoten treffen, als Sie erwarten. Grenzen Sie es ein, wenn Sie können.