Was ist JSONPath?
JSONPath ist eine Abfragesprache zum Extrahieren von Werten aus JSON-Dokumenten. Ursprünglich 2007 von Stefan Goessner als Analogon zu XPath für XML vorgeschlagen, ermöglicht JSONPath das Schreiben von Ausdrücken wie $.store.book[*].author, um alle Autorenfelder innerhalb eines Book-Arrays auszuwählen, ohne Schleifen oder manuellen Traversierungscode zu schreiben. Die Sprache wurde im Februar 2024 als RFC 9535 standardisiert und vom IETF veröffentlicht.
Ein JSONPath-Ausdruck beginnt immer mit $ für den Wurzelknoten des Dokuments. Von dort aus werden Selektoren verkettet: Punktnotation für Objektschlüssel, Klammernotation für Array-Indizes, Wildcards für alle Kinder und der rekursive Abstiegsoperator (..) zur Suche auf jeder Verschachtelungsebene. Filterausdrücke wie [?(@.price < 10)] ermöglichen die Auswahl von Elementen anhand von Bedingungen, die gegen ihre Werte ausgewertet werden.
JSONPath wird in API-Test-Tools wie Postman, Observability-Plattformen wie Datadog und Splunk, Workflow-Engines wie Apache NiFi sowie in Programmierbibliotheken für JavaScript, Python, Go, Java und C# eingesetzt. Das Testen von Ausdrücken gegen echte Daten vor der Einbettung in Code oder Konfigurationsdateien verhindert stille Fehler, wenn die JSON-Struktur nicht den Erwartungen entspricht.
Warum diesen JSONPath Tester verwenden?
JSONPath-Ausdrücke von Hand zu schreiben ist fehleranfällig. Ein fehlender Punkt, ein falscher Klammertyp oder eine falsche Filtersyntax kann leere Ergebnisse ohne Fehlermeldung zurückliefern. Dieses Tool gibt sofortiges visuelles Feedback darüber, was Ihr Ausdruck trifft.
JSONPath-Anwendungsfälle
JSONPath-Syntaxreferenz
RFC 9535 definiert die Standard-JSONPath-Syntax. Die nachfolgende Tabelle beschreibt die Operatoren, die in den meisten Abfragen verwendet werden. Alle Ausdrücke beginnen mit $ (dem Wurzelknoten) und verketten einen oder mehrere Selektoren zur Navigation durch die Dokumentstruktur.
| Operator | Beschreibung | Beispiel |
|---|---|---|
| $ | Root element | $.store |
| .key | Child property | $.store.book |
| [n] | Array index (zero-based) | $.store.book[0] |
| [*] | All elements in array/object | $.store.book[*] |
| .. | Recursive descent | $..author |
| [start:end] | Array slice | $.store.book[0:2] |
| [?()] | Filter expression | $.store.book[?(@.price<10)] |
| @ | Current node (inside filter) | $.store.book[?(@.isbn)] |
JSONPath vs. jq vs. XPath
JSONPath, jq und XPath lösen dasselbe Problem (strukturierte Daten abfragen) für unterschiedliche Formate und Anwendungsfälle. JSONPath zielt auf JSON und ist als Bibliothek in den meisten Sprachen verfügbar. jq ist ein eigenständiges CLI-Tool mit einer eigenen Turing-vollständigen Filtersprache. XPath arbeitet auf XML und ist Teil des W3C-Spezifikations-Stacks.
| Merkmal | JSONPath | jq | XPath |
|---|---|---|---|
| Datenformat | JSON | JSON | XML |
| Erstes Element abrufen | $.store.book[0] | .store.book[0] | /store/book[1] |
| Rekursive Suche | $..price | .. | .price? | //price |
| Filterausdruck | [?(@.price<10)] | select(.price < 10) | [price<10] |
| Spezifikation | RFC 9535 | stedolan.github.io | W3C XPath 3.1 |
Codebeispiele
So werden JSONPath-Ausdrücke in gängigen Sprachen und Tools ausgewertet. Alle Beispiele verwenden dieselbe Buchhandlungs-JSON-Struktur zum Vergleich.
import { JSONPath } from 'jsonpath-plus';
const data = {
store: {
book: [
{ title: 'Moby Dick', price: 8.99 },
{ title: 'The Great Gatsby', price: 12.99 }
]
}
};
// Get all book titles
JSONPath({ path: '$.store.book[*].title', json: data });
// → ['Moby Dick', 'The Great Gatsby']
// Recursive descent — find every price in the document
JSONPath({ path: '$..price', json: data });
// → [8.99, 12.99]
// Filter — books under $10
JSONPath({ path: '$.store.book[?(@.price < 10)]', json: data });
// → [{ title: 'Moby Dick', price: 8.99 }]from jsonpath_ng.ext import parse
import json
data = {
"store": {
"book": [
{"title": "Moby Dick", "price": 8.99},
{"title": "The Great Gatsby", "price": 12.99}
]
}
}
# Get all book titles
expr = parse("$.store.book[*].title")
titles = [match.value for match in expr.find(data)]
# → ['Moby Dick', 'The Great Gatsby']
# Recursive descent — all prices
expr = parse("$..price")
prices = [match.value for match in expr.find(data)]
# → [8.99, 12.99]
# Filter — books under $10
expr = parse("$.store.book[?price < 10]")
cheap = [match.value for match in expr.find(data)]
# → [{"title": "Moby Dick", "price": 8.99}]package main
import (
"fmt"
"github.com/ohler55/ojg/jp"
"github.com/ohler55/ojg/oj"
)
func main() {
src := `{
"store": {
"book": [
{"title": "Moby Dick", "price": 8.99},
{"title": "The Great Gatsby", "price": 12.99}
]
}
}`
obj, _ := oj.ParseString(src)
// Get all book titles
expr, _ := jp.ParseString("$.store.book[*].title")
results := expr.Get(obj)
fmt.Println(results)
// → [Moby Dick The Great Gatsby]
// Recursive descent — all prices
expr2, _ := jp.ParseString("$..price")
fmt.Println(expr2.Get(obj))
// → [8.99 12.99]
}# jq uses its own syntax, not JSONPath, but solves the same problem.
# Mapping common JSONPath patterns to jq:
# $.store.book[*].title → get all titles
echo '{"store":{"book":[{"title":"Moby Dick"},{"title":"Gatsby"}]}}' | \
jq '.store.book[].title'
# → "Moby Dick"
# → "Gatsby"
# $..price → recursive descent for "price" keys
echo '{"a":{"price":1},"b":{"price":2}}' | \
jq '.. | .price? // empty'
# → 1
# → 2
# Filter: books where price < 10
echo '{"store":{"book":[{"title":"A","price":8},{"title":"B","price":12}]}}' | \
jq '.store.book[] | select(.price < 10)'
# → {"title":"A","price":8}