Testador de JSONPath
Escreva uma expressão JSONPath e veja as correspondências ao vivo. Sintaxe da RFC 9535.
Nada do que você cola sai do seu navegador. A lista de permissões connect-src transforma isso em uma garantia do navegador, e não em uma promessa. Confira você mesmo
Escreva uma expressão JSONPath e veja todas as correspondências no seu próprio documento, com o caminho normalizado de cada uma. Edite e rode de novo até selecionar o que você queria.
A sintaxe daqui segue a RFC 9535, o padrão proposto pelo IETF publicado em fevereiro de 2024. Isso importa mais do que parece, porque nos dezessete anos anteriores não havia especificação nenhuma.
Por que o dialeto precisa ser declarado
O JSONPath começou como um post de blog de Stefan Goessner em 2007. Foi implementado por toda parte e nunca especificado, e as implementações divergiram em quase tudo que interessa: se $.. inclui a raiz, o que significa um índice negativo, se $[0,1] faz união, como um filtro se comporta quando a chave falta, e o que acontece com um passo de slice igual a zero. Um projeto de comparação catalogou centenas dessas divergências.
A RFC 9535 resolveu. Um testador que não diz qual dialeto implementa está te dando a resposta sem te dar a pergunta, então este diz: RFC 9535, com as exclusões listadas abaixo.
Sintaxe suportada aqui
- $
- A raiz do documento. Toda expressão começa aqui.
- .name e ['name']
- Um membro nomeado. Use a forma com colchetes para nomes com espaços ou pontuação.
- .* e [*]
- Todos os membros de um objeto, ou todos os elementos de um array.
- ..
- Um segmento descendente: busca neste nível e em todos os abaixo dele.
- [0] e [-1]
- Um índice de array. O negativo conta a partir do fim.
- [1:5], [::2], [::-1]
- Um slice, com a semântica da RFC 9535. Um passo negativo percorre de trás para frente.
- [0, 2, 'name']
- Vários seletores em um mesmo segmento, produzindo a união dos resultados deles.
- [?<expressão>]
- Um filtro. Dentro dele, @ é o elemento atual e $ é a raiz do documento. Comparação com == != < <= > >=, combinável com && || e !.
- length() count() match() search() value()
- As extensões de função que a RFC 9535 define. match() ancora a string inteira; search() não.
Deliberadamente não suportado
Expressões de script na forma [(...)] nunca foram especificadas e a RFC 9535 as removeu. O operador de pai ^ é uma extensão que algumas implementações adicionaram e que a RFC não inclui. E @.length como pseudopropriedade é a grafia pré-RFC do que hoje é length(@); se você colar uma dessas, o testador avisa em vez de devolver nada em silêncio.
JSONPath, JMESPath, jq e JSON Pointer
Quatro formas de endereçar partes de um documento JSON, para quatro trabalhos diferentes.
- JSONPath
- Seleciona um conjunto de nós. Melhor quando você quer tudo que casa com um padrão, em qualquer profundidade. Agora padronizado como RFC 9535.
- JMESPath
- Transforma além de selecionar: projeções, multiselect hashes e expressões com pipe deixam você remodelar a saída. Usado pela CLI da AWS. Com uma especificação de verdade desde o início.
- jq
- Uma linguagem completa com uma sintaxe de consulta acoplada. Recorra a ela quando a operação está mais para programação do que para seleção.
- JSON Pointer, RFC 6901
- Endereça exatamente um local, sem curingas e sem filtros. Deliberadamente trivial, que é por que tanto o JSON Patch quanto o JSON Schema o usam. Dois escapes: ~0 para um til e ~1 para uma barra.
How to do this in code
Rodando a mesma consulta em código.
py Python
# jsonpath-ng is the most complete Python implementation
from jsonpath_ng.ext import parse
expr = parse('$.store.book[?(@.price < 10)].title')
titles = [m.value for m in expr.find(data)]
# JMESPath, if you prefer a specified language with projections
import jmespath
titles = jmespath.search('store.book[?price < `10`].title', data) js JavaScript
import { JSONPath } from 'jsonpath-plus';
const titles = JSONPath({
path: '$.store.book[?(@.price < 10)].title',
json: data,
});
// Get the normalised paths rather than the values
const paths = JSONPath({ path: '$..author', json: data, resultType: 'path' }); sh jq
O jq não tem um operador de descendente com filtro, então as duas metades são escritas separadamente.
# The jq equivalent of a filtered descendant search
jq '.store.book[] | select(.price < 10) | .title' data.json
# Every value at any depth under a key
jq '.. | .author? // empty' data.json java Java
O Jayway JsonPath é anterior à RFC 9535 e difere dela em alguns pontos, especialmente em filtros sobre chaves ausentes.
import com.jayway.jsonpath.JsonPath;
List<String> titles = JsonPath.read(json, "$.store.book[?(@.price < 10)].title"); Perguntas frequentes
- Por que a minha expressão não devolve nada?
- Em geral por uma de três coisas: um nome que precisa de colchetes com aspas porque contém espaço ou hífen, um filtro comparando com uma string sem aspas (escreva @.type == 'book', não @.type == book), ou um caminho que assume um array onde o documento tem um objeto. O testador reporta erro de parsing com a posição quando a expressão está malformada, e resultado vazio só quando a expressão é válida mas não casa com nada.
- O que é um caminho normalizado?
- A RFC 9535 define uma grafia canônica para a localização de uma correspondência: nomes entre colchetes e aspas e índices numéricos, como em $['store']['book'][0]['title']. Cada correspondência aqui mostra um, o que torna os resultados comparáveis entre implementações.
- $..* é a mesma coisa que $..?
- Não, e essa é uma das divergências que a RFC resolveu. $..* seleciona todo nó descendente excluindo a raiz; um $.. sozinho não é sequer uma expressão completa.