JSONPath কী?
JSONPath হলো JSON ডকুমেন্ট থেকে মান বের করার জন্য একটি কোয়েরি ভাষা। ২০০৭ সালে Stefan Goessner এটিকে XML-এর XPath-এর অনুরূপ হিসেবে প্রস্তাব করেন। JSONPath আপনাকে $.store.book[*].author-এর মতো এক্সপ্রেশন লিখতে দেয়, যা লুপ বা ম্যানুয়াল ট্র্যাভার্সাল কোড লেখা ছাড়াই একটি বই অ্যারের সব লেখক ফিল্ড নির্বাচন করে। ভাষাটি ফেব্রুয়ারি ২০২৪ সালে IETF কর্তৃক RFC 9535 হিসেবে মানসম্মত করা হয়েছে।
একটি JSONPath এক্সপ্রেশন সর্বদা $ দিয়ে শুরু হয়, যা ডকুমেন্টের মূলকে প্রতিনিধিত্ব করে। সেখান থেকে আপনি সিলেক্টর চেইন করতে পারেন: অবজেক্ট কী-এর জন্য ডট নোটেশন, অ্যারে ইন্ডেক্সের জন্য ব্র্যাকেট নোটেশন, সব চাইল্ডের জন্য ওয়াইল্ডকার্ড, এবং নেস্টিংয়ের প্রতিটি স্তর অনুসন্ধান করতে রিকার্সিভ ডিসেন্ট অপারেটর (..)। [?(@.price < 10)]-এর মতো ফিল্টার এক্সপ্রেশন আপনাকে মানের বিপরীতে মূল্যায়িত শর্তের ভিত্তিতে উপাদান নির্বাচন করতে দেয়।
JSONPath ব্যবহার করা হয় Postman-এর মতো API টেস্টিং টুলে, Datadog ও Splunk-এর মতো অবজার্ভেবিলিটি প্ল্যাটফর্মে, Apache NiFi-এর মতো ওয়ার্কফ্লো ইঞ্জিনে, এবং JavaScript, Python, Go, Java ও C#-জুড়ে প্রোগ্রামিং লাইব্রেরিতে। কোডে বা কনফিগে এম্বেড করার আগে আসল ডেটা দিয়ে এক্সপ্রেশন যাচাই করে নিলে JSON স্ট্রাকচার অনুমানের সাথে না মিললে নীরবে ব্যর্থ হওয়ার ঝামেলা এড়ানো যায়।
কেন এই JSONPath পরীক্ষক ব্যবহার করবেন?
হাতে JSONPath এক্সপ্রেশন লেখা ত্রুটিপ্রবণ। একটি ডট বাদ পড়া, ভুল ব্র্যাকেটের ধরন, বা ভুল ফিল্টার সিনট্যাক্স কোনো ত্রুটি বার্তা ছাড়াই খালি ফলাফল ফেরত দিতে পারে। এই টুল আপনার এক্সপ্রেশন কী ম্যাচ করছে তার তাৎক্ষণিক দৃশ্যমান প্রতিক্রিয়া দেয়।
JSONPath ব্যবহারের ক্ষেত্রসমূহ
JSONPath সিনট্যাক্স রেফারেন্স
RFC 9535 আদর্শ JSONPath সিনট্যাক্স নির্ধারণ করে। নিচের টেবিলটি বেশিরভাগ কোয়েরিতে ব্যবহৃত অপারেটরগুলো কভার করে। সমস্ত এক্সপ্রেশন $ (রুট নোড) দিয়ে শুরু হয় এবং ডকুমেন্ট কাঠামো নেভিগেট করতে এক বা একাধিক সিলেক্টর চেইন করে।
| অপারেটর | বিবরণ | উদাহরণ |
|---|---|---|
| $ | 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 বনাম jq বনাম XPath
JSONPath, jq এবং XPath একই সমস্যা সমাধান করে (কাঠামোগত ডেটা কোয়েরি করা) কিন্তু ভিন্ন ফরম্যাট ও ব্যবহারের ক্ষেত্রে। JSONPath JSON লক্ষ্য করে এবং বেশিরভাগ ভাষায় একটি লাইব্রেরি হিসেবে পাওয়া যায়। jq নিজস্ব টুরিং-সম্পূর্ণ ফিল্টার ভাষা সহ একটি স্বতন্ত্র CLI টুল। XPath XML-এ কাজ করে এবং W3C স্পেসিফিকেশন স্ট্যাকের অংশ।
| বৈশিষ্ট্য | JSONPath | jq | XPath |
|---|---|---|---|
| ডেটা ফরম্যাট | JSON | JSON | XML |
| প্রথম উপাদান অ্যাক্সেস | $.store.book[0] | .store.book[0] | /store/book[1] |
| রিকার্সিভ অনুসন্ধান | $..price | .. | .price? | //price |
| ফিল্টার এক্সপ্রেশন | [?(@.price<10)] | select(.price < 10) | [price<10] |
| স্পেসিফিকেশন | RFC 9535 | stedolan.github.io | W3C XPath 3.1 |
কোড উদাহরণ
জনপ্রিয় ভাষা ও টুলে JSONPath এক্সপ্রেশন মূল্যায়ন করার উপায়। তুলনার জন্য প্রতিটি উদাহরণ একই বুকস্টোর JSON কাঠামো ব্যবহার করে।
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}