O Que É JSONPath?
JSONPath é uma linguagem de consulta para extrair valores de documentos JSON. Proposta originalmente por Stefan Goessner em 2007 como um análogo ao XPath para XML, o JSONPath permite escrever expressões como $.store.book[*].author para selecionar todos os campos de autor dentro de um array de livros sem precisar de loops ou código de travessia manual. A linguagem foi padronizada em fevereiro de 2024 como RFC 9535, publicada pelo IETF.
Uma expressão JSONPath sempre começa com $ representando a raiz do documento. A partir daí, você encadeia seletores: notação de ponto para chaves de objetos, notação de colchetes para índices de arrays, curingas para todos os filhos e o operador de descida recursiva (..) para pesquisar em todos os níveis de aninhamento. Expressões de filtro como [?(@.price < 10)] permitem selecionar elementos com base em condições avaliadas sobre seus valores.
JSONPath é usado em ferramentas de teste de API como o Postman, plataformas de observabilidade como Datadog e Splunk, mecanismos de fluxo de trabalho como o Apache NiFi, e bibliotecas de programação em JavaScript, Python, Go, Java e C#. Testar suas expressões em dados reais antes de incorporá-las em código ou arquivos de configuração evita falhas silenciosas quando a estrutura JSON não corresponde às suas suposições.
Por Que Usar Este Testador JSONPath?
Escrever expressões JSONPath manualmente é suscetível a erros. Um ponto faltando, tipo de colchete errado ou sintaxe de filtro incorreta pode retornar resultados vazios sem nenhuma mensagem de erro. Esta ferramenta fornece feedback visual imediato sobre o que sua expressão corresponde.
Casos de Uso do JSONPath
Referência de Sintaxe JSONPath
O RFC 9535 define a sintaxe padrão do JSONPath. A tabela abaixo cobre os operadores que você usará na maioria das consultas. Todas as expressões começam com $ (o nó raiz) e encadeiam um ou mais seletores para navegar pela estrutura do documento.
| Operador | Descrição | Exemplo |
|---|---|---|
| $ | 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 e XPath resolvem o mesmo problema (consultar dados estruturados) para diferentes formatos e casos de uso. JSONPath é voltado para JSON e está disponível como biblioteca na maioria das linguagens. jq é uma ferramenta CLI independente com sua própria linguagem de filtros Turing-completa. XPath opera sobre XML e faz parte do conjunto de especificações da W3C.
| Recurso | JSONPath | jq | XPath |
|---|---|---|---|
| Formato de dados | JSON | JSON | XML |
| Acessar primeiro elemento | $.store.book[0] | .store.book[0] | /store/book[1] |
| Pesquisa recursiva | $..price | .. | .price? | //price |
| Expressão de filtro | [?(@.price<10)] | select(.price < 10) | [price<10] |
| Especificação | RFC 9535 | stedolan.github.io | W3C XPath 3.1 |
Exemplos de Código
Como avaliar expressões JSONPath em linguagens e ferramentas populares. Cada exemplo usa a mesma estrutura JSON de livraria para comparação.
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}