Ir para o conteúdo
jsonbeautifiers
Português

Testador de JSONPath

Escreva uma expressão JSONPath e veja as correspondências ao vivo. Sintaxe da RFC 9535.

Documento
Correspondências

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.