Wat is JSONPath?
JSONPath is een querytaal voor het extraheren van waarden uit JSON-documenten. Oorspronkelijk voorgesteld door Stefan Goessner in 2007 als equivalent van XPath voor XML, stelt JSONPath je in staat expressies te schrijven zoals $.store.book[*].author om alle auteurvelden in een book-array te selecteren zonder lussen of handmatige traversalcode. De taal werd in februari 2024 gestandaardiseerd als RFC 9535, gepubliceerd door de IETF.
Een JSONPath-expressie begint altijd met $ voor de root van het document. Vanaf daar koppel je selectors: puntnotatie voor objectsleutels, haakjesnotatie voor array-indices, wildcards voor alle kinderen en de recursieve afdaaloperator (..) om door elk nestniveau te zoeken. Filterexpressies zoals [?(@.price < 10)] laten je elementen selecteren op basis van voorwaarden die worden geëvalueerd ten opzichte van hun waarden.
JSONPath wordt gebruikt in API-testtools zoals Postman, observabiliteitsplatformen zoals Datadog en Splunk, workflow-engines zoals Apache NiFi en programmeerbibliotheken voor JavaScript, Python, Go, Java en C#. Door je expressies te testen tegen echte data voordat je ze in code of configuratiebestanden opneemt, voorkom je stille fouten wanneer de JSON-structuur niet overeenkomt met je aannames.
Waarom deze JSONPath Tester gebruiken?
JSONPath-expressies handmatig schrijven is foutgevoelig. Een ontbrekende punt, verkeerd haakjestype of onjuiste filtersyntaxis kan lege resultaten opleveren zonder foutmelding. Dit hulpmiddel geeft je directe visuele feedback over wat je expressie overeenkomt.
JSONPath-toepassingen
JSONPath-syntaxisreferentie
RFC 9535 definieert de standaard JSONPath-syntaxis. De onderstaande tabel behandelt de operators die je in de meeste queries zult gebruiken. Alle expressies beginnen met $ (het rootknooppunt) en koppelen een of meer selectors om door de documentstructuur te navigeren.
| Operator | Beschrijving | Voorbeeld |
|---|---|---|
| $ | 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 en XPath lossen hetzelfde probleem op (gestructureerde data queryen) voor verschillende formaten en toepassingen. JSONPath richt zich op JSON en is beschikbaar als bibliotheek in de meeste talen. jq is een zelfstandige CLI-tool met zijn eigen Turing-complete filtertaal. XPath werkt op XML en maakt deel uit van de W3C-specificatiestack.
| Functie | JSONPath | jq | XPath |
|---|---|---|---|
| Gegevensformaat | JSON | JSON | XML |
| Toegang tot eerste element | $.store.book[0] | .store.book[0] | /store/book[1] |
| Recursief zoeken | $..price | .. | .price? | //price |
| Filterexpressie | [?(@.price<10)] | select(.price < 10) | [price<10] |
| Specificatie | RFC 9535 | stedolan.github.io | W3C XPath 3.1 |
Codevoorbeelden
Hoe JSONPath-expressies te evalueren in populaire talen en tools. Elk voorbeeld gebruikt dezelfde boekwinkel-JSON-structuur voor vergelijking.
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}