Pular para o conteudo principal
CuteJSON
↑↓ Navegar Enter Selecionar Esc Fechar

Folha de referencia JSONPath, com exemplos elaborados

Publicado 5 min de leitura Por Akash Kinkar Pandey

JSONPath e uma linguagem de consultas para JSON, da mesma forma que XPath e uma para XML. Ele foi esboado por Stefan Goessner em 2007, implementado de forma diferente por todos que precisavam dele, e finalmente padronizado como RFC 9535 em 2024. Essa historia e por que duas implementacoes de JSONPath frequentemente discordam, e por que uma folha de referencia e mais util com resultados anexados do que como uma lista de simbolos.

Cada consulta abaixo e executada contra este documento. Voce pode colar no testador JSONPath, que carrega exatamente este como amostra.

{
  "store": {
    "book": [
      { "category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95 },
      { "category": "fiction", "author": "Evelyn Waugh", "title": "Sword of Honour", "price": 12.99 },
      { "category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99 }
    ],
    "bicycle": { "color": "red", "price": 19.95 }
  },
  "expensive": 10
}

Os seletores

Raiz. $ e o documento inteiro. Cada consulta comeca la.

Filho por nome. $.store.bicycle.color retorna "red". Um ponto seguido de um nome, quantas vezes for necessario.

Nome entre aspas. $['store']['bicycle'] e a mesma coisa escrita de outra maneira. Voce precisa dos colchetes quando uma chave tem espaco, ponto ou hifen, ou quando comeca com um digito: $['first name'].

Curinga. $.store.bicycle.* retorna "red" e 19.95, todos os filhos de esse objeto. $.store.book[*] retorna todos os tres livros.

Indice. $.store.book[0] e o primeiro livro. $.store.book[-1] e o ultimo, contando de tras para frente.

Fatia. $.store.book[0:2] retorna os dois primeiros livros. O final e exclusivo, exatamente como em Python. $.store.book[::2] pega cada segundo livro, e um passo negativo inverte: $.store.book[::-1].

Uniao. $.store.book[0, 2] retorna o primeiro e terceiro livros. $.store.bicycle['color', 'price'] seleciona dois filhos nomeados de uma vez.

Descendente. $..price retorna cada preco em qualquer profundidade, que aqui e 8.95, 12.99, 8.99 e 19.95. Este e o seletor para o qual as pessoas mais recorrem e o que custa mais em um documento grande, porque visita cada valor.

Filtro. $.store.book[?@.price < 10] retorna os dois livros mais baratos. O @ se refere ao valor sendo testado. A RFC 9535 removeu os parenteses que tutoriais mais antigos usam, entao [?@.price < 10] e [?(@.price < 10)] aparecem ambos no meio. O testador aqui aceita ambos.

Existencia. $.store.book[?@.isbn] retorna apenas o livro que tem um campo isbn, sem comparar com nada.

Combinando testes. &&, || e ! funcionam como voce esperaria: $..book[?@.category == 'fiction' && @.price < 10].title retorna "Moby Dick".

Por que um filtro que parece correto nao retorna nada

Quase sempre, e uma incompatibilidade de tipo. A especificacao diz que valores de tipos diferentes nunca sao iguais e nunca sao ordenados, entao um preco armazenado como "8.95" com aspas nao corresponde a @.price < 10, e tambem nao corresponde a @.price == 8.95. Se um filtro nao retorna nada, verifique os tipos no documento antes de verificar a consulta.

A segunda causa e anexar o filtro ao nivel errado. Um filtro escolhe entre os filhos do valor ao qual esta anexado, entao ele vai depois do array: book[?@.price < 10], nao book.price[?...]. Anexado a um objeto, ele testa cada valor de propriedade desse objeto ao inves disso.

Terceiro, um valor ausente nao e null. @.isbn == null corresponde a um livro cujo isbn e literalmente null, nao a um livro que nao tem isbn de forma alguma. Para testar ausencia, escreva !@.isbn.

Onde as implementacoes discordam

O artigo de 2007 foi uma proposta, nao uma especificacao, entao as bibliotecas divergiram por dezessete anos. Se voce esta movendo uma consulta entre ferramentas, esses sao os lugares a verificar:

  • Indices negativos e passos negativos sao amplamente suportados agora e faltam em algumas bibliotecas mais antigas.
  • A forma de filtro com parenteses e a ortografia antiga. A RFC 9535 usa [?...] nu, e muitas ferramentas aceitam apenas uma das duas.
  • A RFC define as funcoes length(), count(), match() e search(). Muitas implementacoes nao as tem ou fornecem um conjunto diferente sob nomes diferentes.
  • A RFC da aos resultados uma ordem de documento. Algumas implementacoes nao garantem isso, particularmente para segmentos descendentes.

O testador neste site implementa os seletores listados acima e diz isso claramente na pagina, incluindo uma tabela do que suporta. Extensões de funcoes, caminhos absolutos dentro de um filtro, e comparar dois caminhos entre si nao sao implementados, e usar um deles produz uma mensagem nomeando a funcionalidade em vez de um erro de sintaxe. Essa e uma escolha deliberada: uma ferramenta que afirma conformidade total e depois falha silenciosamente em um caso de borda e pior que uma que diz onde esta seu limite.

JSONPath ou Ponteiro JSON

Eles respondem a perguntas diferentes.

Um Ponteiro JSON nomeia exatamente um valor e resolve ou nao resolve. Ele nao tem curingas nem filtros, e e precisamente por isso que JSON Schema, JSON Patch e a maioria das mensagens de erro de validacao o usam: um endereco inequivoco e o que eles precisam. /store/book/0/title significa um lugar.

Uma consulta JSONPath e uma pesquisa. Ela pode retornar muitos valores ou nenhum, e pode filtrar. Use-a quando voce nao sabe de antemao onde esta o que voce quer.

Se voce conhece o endereco, use um ponteiro. Se voce esta procurando algo, use uma consulta. Ambas as ferramentas neste site relatam a linha onde cada resultado esta sentado, entao de qualquer forma voce termina de volta no documento em vez de em uma lista abstrata de resultados.

Voltar a todos os posts