Apa itu JSONPath?
JSONPath adalah bahasa kueri untuk mengekstrak nilai dari dokumen JSON. Awalnya diusulkan oleh Stefan Goessner pada tahun 2007 sebagai padanan XPath untuk XML, JSONPath memungkinkan Anda menulis ekspresi seperti $.store.book[*].author untuk memilih semua field author di dalam array book tanpa menulis loop atau kode traversal manual. Bahasa ini distandarisasi pada Februari 2024 sebagai RFC 9535 yang diterbitkan oleh IETF.
Ekspresi JSONPath selalu dimulai dengan $ yang mewakili akar dokumen. Dari sana Anda merangkai selektor: notasi titik untuk kunci objek, notasi kurung untuk indeks array, wildcard untuk semua anak, dan operator rekursif (..) untuk menelusuri setiap level nesting. Ekspresi filter seperti [?(@.price < 10)] memungkinkan Anda memilih elemen berdasarkan kondisi yang dievaluasi terhadap nilainya.
JSONPath digunakan dalam alat pengujian API seperti Postman, platform observabilitas seperti Datadog dan Splunk, mesin workflow seperti Apache NiFi, serta pustaka pemrograman di JavaScript, Python, Go, Java, dan C#. Menguji ekspresi Anda terhadap data nyata sebelum menyematkannya dalam kode atau file konfigurasi mencegah kegagalan diam-diam ketika struktur JSON tidak sesuai dengan asumsi Anda.
Mengapa Menggunakan JSONPath Tester Ini?
Menulis ekspresi JSONPath secara manual rentan terhadap kesalahan. Titik yang hilang, tipe kurung yang salah, atau sintaks filter yang keliru dapat mengembalikan hasil kosong tanpa pesan error. Alat ini memberikan umpan balik visual langsung tentang apa yang dicocokkan ekspresi Anda.
Kasus Penggunaan JSONPath
Referensi Sintaks JSONPath
RFC 9535 mendefinisikan sintaks JSONPath standar. Tabel di bawah mencakup operator yang akan Anda gunakan dalam sebagian besar kueri. Semua ekspresi dimulai dengan $ (node akar) dan merangkai satu atau lebih selektor untuk menavigasi struktur dokumen.
| Operator | Deskripsi | Contoh |
|---|---|---|
| $ | 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, dan XPath memecahkan masalah yang sama (membuat kueri data terstruktur) untuk format dan kasus penggunaan yang berbeda. JSONPath menargetkan JSON dan tersedia sebagai pustaka di sebagian besar bahasa. jq adalah alat CLI mandiri dengan bahasa filter Turing-complete-nya sendiri. XPath beroperasi pada XML dan merupakan bagian dari tumpukan spesifikasi W3C.
| Fitur | JSONPath | jq | XPath |
|---|---|---|---|
| Format data | JSON | JSON | XML |
| Akses elemen pertama | $.store.book[0] | .store.book[0] | /store/book[1] |
| Pencarian rekursif | $..price | .. | .price? | //price |
| Ekspresi filter | [?(@.price<10)] | select(.price < 10) | [price<10] |
| Spesifikasi | RFC 9535 | stedolan.github.io | W3C XPath 3.1 |
Contoh Kode
Cara mengevaluasi ekspresi JSONPath dalam bahasa dan alat populer. Setiap contoh menggunakan struktur JSON toko buku yang sama untuk perbandingan.
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}