JSONPath Tutorial: Query JSON Like a Pro
Master JSONPath syntax with practical examples. Learn every operator, filter expression, and real-world query pattern to extract data from complex JSON structures.
Was ist JSONPath?
JSONPath ist eine Abfragesprache für JSON – vergleichbar mit XPath für XML. Mit knapper Ausdruckssyntax greifen Sie in komplexe JSON-Strukturen und holen genau die Daten heraus, die Sie brauchen. Statt mit Schleifen und Bedingungen durch verschachtelte Objekte und Arrays zu navigieren, schreiben Sie einen einzigen Pfadausdruck wie $.store.book[?(@.price < 10)].title und erhalten alle Buchtitel unter zehn Dollar.
Stefan Goessner stellte JSONPath 2007 vor; seither hat es sich über Sprachen und Tools hinweg als De-facto-Standard etabliert. Arbeiten Sie mit REST-APIs, Konfigurationsdateien oder nicht trivialen JSON-Daten, spart Ihnen JSONPath erheblich Zeit.
JSONPath vs. XPath: Kurzvergleich
Kennen Sie XPath bereits, wirkt JSONPath vertraut. Entscheidend ist: JSON hat ein schlichteres Datenmodell – Objekte und Arrays statt Elemente, Attribute und Namespaces. So hängen die Konzepte zusammen:
| Konzept | XPath | JSONPath |
|---|---|---|
| Wurzel | / | $ |
| Kindelement | /child | .child oder ['child'] |
| Rekursiver Abstieg | // | .. |
| Wildcard | * | * |
| Array-Index | [1] (1-basiert) | [0] (0-basiert) |
| Filter | [predicate] | [?(expression)] |
Die vollständige JSONPath-Operatorreferenz
Jeder JSONPath-Ausdruck startet an der Wurzel $ und verkettet Operatoren zur Navigation. Dies sind die Operatoren, die Sie kennen sollten:
| Operator | Beschreibung | Beispiel |
|---|---|---|
$ | Wurzelobjekt oder -array | $ — das gesamte Dokument |
.key | Untereigenschaft nach Name (Punktnotation) | $.store.name |
['key'] | Untereigenschaft nach Name (Klammernotation) | $['store']['name'] |
.. | Rekursiver Abstieg — durchsucht alle Nachfahren | $..price — jedes Feld price |
* | Wildcard — alle Member eines Objekts oder Arrays | $.store.* |
[n] | Array-Index (0-basiert) | $.items[0] |
[start:end] | Array-Slice (Ende exklusiv) | $.items[0:3] — die ersten drei Elemente |
[start:end:step] | Array-Slice mit Schritt | $.items[::2] — jedes zweite Element |
[n,m] | Mehrere Array-Indizes | $.items[0,2,4] |
[?()] | Filterausdruck | $.items[?(@.price > 10)] |
@ | Aktueller Knoten (innerhalb von Filtern) | @.name == 'Alice' |
Beispiel-JSON für unsere Beispiele
Wir verwenden dieses JSON-Dokument durchgängig im Tutorial. Es stellt eine kompakte API-Antwort eines Buchladens dar:
{
"store": {
"name": "TechBooks Online",
"book": [
{
"category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95,
"inStock": true
},
{
"category": "fiction",
"author": "Evelyn Waugh",
"title": "Sword of Honour",
"price": 12.99,
"inStock": false
},
{
"category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"price": 8.99,
"inStock": true
},
{
"category": "fiction",
"author": "J. R. R. Tolkien",
"title": "The Lord of the Rings",
"isbn": "0-395-19395-8",
"price": 22.99,
"inStock": true
}
],
"bicycle": {
"color": "red",
"price": 19.95
}
}
}
Praktische JSONPath-Beispiele
1. Namen des Shops abrufen
$.store.name
Ergebnis:
"TechBooks Online"
2. Alle Buchtitel abrufen
$.store.book[*].title
Ergebnis:
[
"Sayings of the Century",
"Sword of Honour",
"Moby Dick",
"The Lord of the Rings"
]
3. Das erste Buch abrufen
$.store.book[0]
Ergebnis: das vollständige Objekt des ersten Buchs.
4. Das letzte Buch abrufen
$.store.book[-1]
Negative Indizes zählen vom Ende; -1 liefert das letzte Element.
5. Slice: die ersten zwei Bücher
$.store.book[0:2]
Liefert die Bücher an den Indizes 0 und 1. Der Endindex ist exklusiv – wie bei slice() in Python und JavaScript.
6. Alle Preise im gesamten Dokument
$..price
Ergebnis:
[8.95, 12.99, 8.99, 22.99, 19.95]
Der Operator für rekursiven Abstieg .. findet jedes Feld price unabhängig von der Tiefe – einschließlich des Fahrradpreises.
7. Filter: Bücher unter 10 $
$.store.book[?(@.price < 10)]
Liefert die beiden Bücher mit 8,95 und 8,99. Das Symbol @ bezeichnet das jeweils geprüfte Element.
8. Filter: Bücher mit ISBN
$.store.book[?(@.isbn)]
Liefert nur Moby Dick und The Lord of the Rings.
9. Filter: Fiction-Bücher auf Lager
$.store.book[?(@.category == 'fiction' && @.inStock == true)]
Bedingungen lassen sich mit && (UND) und || (ODER) verknüpfen.
10. Mehrere Indizes
$.store.book[0,3]
Gezielt einzelne Elemente wählen: erstes und viertes Buch.
11. Wildcard auf einem Objekt
$.store.bicycle.*
Ergebnis:
["red", 19.95]
Liefert alle Werte des Objekts bicycle.
12. Autoren teurer Bücher
$.store.book[?(@.price > 15)].author
Ergebnis:
["J. R. R. Tolkien"]
Probieren Sie es aus: Fügen Sie das Beispiel-JSON von oben ein und testen Sie diese Ausdrücke im JSONPath Tester von JSONTech.
Filterausdrücke im Detail
Filterausdrücke sind der stärkste Teil von JSONPath. Sie stehen in [?()] und werten für jedes Element eine boolesche Bedingung aus. Verfügbare Operatoren:
| Operator | Bedeutung | Beispiel |
|---|---|---|
== | gleich | @.status == 'active' |
!= | ungleich | @.role != 'admin' |
> | größer als | @.age > 18 |
>= | größer oder gleich | @.score >= 90 |
< | kleiner als | @.price < 50 |
<= | kleiner oder gleich | @.quantity <= 0 |
=~ | Regex-Übereinstimmung (implementationsabhängig) | @.name =~ /^J.*/ |
&& | logisches UND | @.price > 5 && @.price < 20 |
| ` | ` |
Häufig prüft man, ob eine Eigenschaft existiert: @.isbn ohne Vergleichsoperator ist wahr, wenn die Eigenschaft vorhanden und nicht null ist.
Szenarien aus der Praxis
Alle E-Mail-Adressen aus einer API-Antwort extrahieren
Angenommen, eine Benutzerverwaltungs-API liefert tief verschachtelte Kontaktobjekte:
{
"users": [
{
"name": "Alice",
"contacts": { "email": "alice@example.com", "phone": "555-0101" }
},
{
"name": "Bob",
"contacts": { "email": "bob@example.com", "phone": "555-0102" }
}
]
}
Abfrage: $..email
Ergebnis:
["alice@example.com", "bob@example.com"]
Rekursiver Abstieg findet jedes Feld email, unabhängig von der Position in der Hierarchie.
Produkte nach Preisspanne finden
$.products[?(@.price >= 25 && @.price <= 100)]
Praktisch, um API-Antworten clientseitig zu filtern, bevor eine Produktliste gerendert wird.
Verschachtelte Konfigurationswerte lesen
$.config.database.connections[0].host
Direkter Zugriff auf Konfigurationsdateien ohne verketteten optionalen Zugriff wie config?.database?.connections?.[0]?.host.
JSONPath in verschiedenen Sprachen
JavaScript / Node.js
Das Paket jsonpath-plus ist weit verbreitet:
import { JSONPath } from "jsonpath-plus";
const data = { store: { book: [{ title: "Moby Dick", price: 8.99 }] } };
const titles = JSONPath({ path: "$.store.book[*].title", json: data });
console.log(titles); // ["Moby Dick"]
Python
Mit jsonpath-ng erhalten Sie eine spezifikationsnahe Implementierung:
from jsonpath_ng.ext import parse
data = {"store": {"book": [{"title": "Moby Dick", "price": 8.99}]}}
expr = parse("$.store.book[*].title")
matches = [match.value for match in expr.find(data)]
print(matches) # ['Moby Dick']
Java
Die Jayway-JSONPath-Bibliothek ist in JVM-Projekten üblich:
import com.jayway.jsonpath.JsonPath;
String json = "{\"store\":{\"book\":[{\"title\":\"Moby Dick\",\"price\":8.99}]}}";
List<String> titles = JsonPath.read(json, "$.store.book[*].title");
System.out.println(titles); // [Moby Dick]
Stolpersteine und Grenzen
JSONPath ist mächtig – dennoch sollten Sie Folgendes beachten, bevor Sie es produktiv einsetzen:
- Lange keine formale Spezifikation. JSONPath war lange nur informell beschrieben; Bibliotheken unterschieden sich in Details. Die IETF veröffentlichte 2024 RFC 9535 zur Standardisierung der Syntax; viele Bibliotheken orientieren sich aber noch an Goessners Original. Prüfen Sie die Dokumentation Ihrer Bibliothek.
- Regex-Support variiert. Der Operator
=~ist nicht überall verfügbar. Jayway unter Java unterstützt ihn; viele JavaScript-Bibliotheken nicht. - Keine Schreibzugriffe. JSONPath ist read-only. Das Quelldokument ändern Sie damit nicht; für Änderungen brauchen Sie JSON Patch (RFC 6902) oder manuelles Durchlaufen.
- Performance bei sehr großen Dokumenten. Rekursiver Abstieg (
..) besucht viele Knoten. Bei Millionen von Knoten kann das teuer werden – nutzen Sie dann möglichst spezifische Pfade. - Uneinheitliche Rückgabetypen. Manche Bibliotheken liefern bei einem Treffer einen Einzelwert, bei mehreren ein Array; andere immer ein Array. Normalisieren Sie den Rückgabewert in Ihrem Code.
- Sonderzeichen in Schlüsseln. Enthalten Schlüssel Punkte, Leerzeichen oder andere Sonderzeichen, verwenden Sie Klammernotation:
$('my.key')statt$.my.key.
JSONPath vs. jq
Wie verhält sich JSONPath zu jq, dem bekannten JSON-Prozessor für die Kommandozeile? Kurz: ähnliche Problemstellung, andere Zielgruppe.
- JSONPath ist für die Einbettung in Anwendungscode gedacht, mit Bibliotheken in den gängigen Sprachen und einer gut lesbaren Abfragesyntax.
- jq ist eine ausgewachsene Transformationssprache: filtern, mappen, reduzieren, Umformen von JSON. Mächtiger, steiler zu lernen, typisch für Shell und Pipelines.
Für Abfragen im Anwendungscode ist JSONPath pragmatisch; für Shell-Skripte und Datenpipelines ist jq schwer zu schlagen.
Schnellreferenz (Cheat Sheet)
| Ziel | JSONPath |
|---|---|
| Gesamtes Dokument | $ |
| Bestimmte Eigenschaft | $.user.name |
| Alle Array-Elemente | $.items[*] |
| Erstes Element | $.items[0] |
| Letztes Element | $.items[-1] |
| Elementbereich | $.items[1:4] |
| Jedes n-te Element | $.items[::2] |
Alle name-Felder überall | $..name |
| Nach Wert filtern | $.items[?(@.price < 10)] |
| Nach Existenz filtern | $.items[?(@.discount)] |
| Mehrere Bedingungen | $.items[?(@.qty > 0 && @.active)] |
Probieren Sie es aus: Öffnen Sie den JSONPath Tester auf JSONTech.net und führen Sie Abfragen live gegen Ihre eigenen JSON-Daten aus.