Existe um equivalente JSON do XQuery / XPath?

221

Ao procurar itens em matrizes e hashes JSON complexos, como:

[
    { "id": 1, "name": "One", "objects": [
        { "id": 1, "name": "Response 1", "objects": [
            // etc.
        }]
    }
]

Existe algum tipo de linguagem de consulta que posso usar para encontrar um item in [0].objects where id = 3?

Naftuli Kay
fonte
não a menos que você faça um. Deixe a consulta para o servidor e use REST para obter apenas os dados necessários.
zzzzBov
5
+1 de boa ideia. Vou escrever isso amanhã ...
2
Não é XPath, mas eu achei o JLinq muito bom (o que torna o código parecido com isso in(...).where(...).select(...)): hugoware.net/Projects/jLinq .
Pimvdb
4
Isso é frustrante porque há muitas bibliotecas por aí, mas nada se aproxima de um padrão comumente aceito. Como temos uma biblioteca usada por terceiros, precisamos fornecer uma linguagem de consulta amplamente conhecida e usada.
David Thielen
1
Claro, você pode usar o jsel - github.com/dragonworx/jsel - desde que você tenha uma variável dataque contenha seu objeto JSON, você escreveria: jsel(data).select("//*[@id=3]")e retornaria o objeto que contém a chave id com 3.
Ali

Respostas:

122

Sim, é chamado JSONPath . A fonte agora está no GitHub .

Também está integrado ao DOJO .

Mike Christensen
fonte
3
A resposta de Brian sugere que o módulo jsonQuery deve ser usado em vez do módulo jsonPath no dojo.
hugomg
5
Quão sólido é isso? E não consigo encontrar uma versão Java ou C # que seja uma boa opção para nós.
David Thielen
2
O site vinculado aqui fornece Javascript e PHP. Se você precisa de uma aplicação Java, há um aqui: code.google.com/p/json-path
Matthias Ronge
2
Devo mencionar que JSONPath não é baseado na semântica formal XPath. JSONiq pode ser uma opção melhor.
Wcandillon
1
@Paramaeleon Isso funciona muito bem. O projeto foi migrado para o GitHub , a propósito. Mike pode adicionar isso à resposta, pois as pessoas continuam comentando sobre isso.
Franklin Yu
21

Eu acho que o JSONQuery é um superconjunto do JSONPath e, portanto, o substitui no dojo . Depois, há também o RQL .

Da documentação do Dojo:

O JSONQuery é uma versão estendida do JSONPath com recursos adicionais de segurança, facilidade de uso e um conjunto abrangente de ferramentas de consulta de dados, incluindo filtragem, pesquisa recursiva, classificação, mapeamento, seleção de intervalo e expressões flexíveis com comparações de caracteres curinga e vários operadores.

JSONselect tem outro ponto de vista sobre a questão (semelhante ao seletor CSS, em vez de XPath) e possui uma implementação JavaScript .

Brian Clozel
fonte
4
O link JSONQuery do github parece estar morto. JSONSelect também tem uma versão JavaScript agora.
Henrik Aasted Sørensen
19

Outras alternativas que conheço são

  1. Especificação JSONiq , que especifica dois subtipos de linguagens: uma que oculta detalhes XML e fornece sintaxe semelhante a JS, e outra que enriquece a sintaxe XQuery com construtores JSON e outros. O Zorba implementa o JSONiq.
  2. O Corona , construído sobre o MarkLogic, fornece uma interface REST para armazenar, gerenciar e pesquisar conteúdo XML, JSON, Texto e Binário.
  3. O MarkLogic 6 e versões posteriores fornecem uma interface REST semelhante à Corona pronta para uso.
  4. O MarkLogic 8 e versões posteriores suportam JSON nativamente nos ambientes XQuery e JavaScript do lado do servidor. Você pode aplicar o XPath nele.

HTH.

grtjn
fonte
3
Agora existe uma implementação do JSONiq: o Zorba 2.6 suporta oficialmente.
Ghislain Fourny
Nota: O MarkLogic armazena JSON nativamente a partir da versão 8 e permite aplicar o XPath diretamente nele.
grtjn
18

Para resumir algumas das opções atuais para atravessar / filtrar dados JSON e fornecer alguns exemplos de sintaxe ...

  • JSPath
    .automobiles{.maker === "Honda" && .year > 2009}.model

  • json: select () (inspirado mais nos seletores de CSS)
    .automobiles .maker:val("Honda") .model

  • JSONPath (inspirado mais no XPath)
    $.automobiles[?(@.maker='Honda')].model

Eu acho que o JSPath é o mais bonito, então vou tentar integrá-lo ao meu aplicativo AngularJS + CakePHP.

(Originalmente, eu postei essa resposta em outro tópico, mas achei que seria útil aqui também.)

Simon East
fonte
Ótimo resumo e exemplos, também por mencionar a inspiração encontrada nos seletores de CSS ou no XPath.
Jochem Schulenklopper 17/10/1918
13

Tente usar JSPath

JSPath é uma linguagem específica de domínio (DSL) que permite navegar e localizar dados nos seus documentos JSON. Usando JSPath, você pode selecionar itens de JSON para recuperar os dados que eles contêm.

JSPath para JSON como um XPath para XML.

É fortemente otimizado para Node.js e navegadores modernos.

dfilatov
fonte
9

O XQuery pode ser usado para consultar o JSON, desde que o processador ofereça suporte a JSON. Este é um exemplo direto de como o BaseX pode ser usado para encontrar objetos com "id" = 1:

json:parse('[
    { "id": 1, "name": "One", "objects": [
        { "id": 1, "name": "Response 1", "objects": [ "etc." ] }
    ]}
]')//value[.//id = 1]
Christian Grün
fonte
(6 anos depois) O Saxon executará o XQuery 3.1, que consulta o JSON. Minha experiência com o saxão é usar o arquivo jar executado por java. Existe um módulo de nó chamado saxon-java, mas não tenho certeza de como isso funciona com o json. E há outra coisa nova da Saxonica chamada Saxon-JS.
charles ross
9

Existe algum tipo de linguagem de consulta ...

jq define um J SON q linguagem uery que é muito semelhante ao JSONPath - ver https://github.com/stedolan/jq/wiki/For-JSONPath-users

... [qual] eu posso usar para encontrar um item em [0]. objetos em que id = 3?

Assumirei o seguinte: encontre todos os objetos JSON sob a chave especificada com id == 3, não importa onde o objeto possa estar. Uma consulta jq correspondente seria:

.[0].objects | .. | objects | select(.id==3)

onde "|" é o operador de pipe (como no comando shell pipes) e onde o segmento ".. | objetos" corresponde a "não importa onde o objeto possa estar".

O básico do jq é bastante óbvio ou intuitivo ou, pelo menos, bastante simples, e o resto é fácil de entender, se você estiver familiarizado com os pipes do shell de comando. A FAQ do jq possui indicadores para tutoriais e similares.

O jq também é como o SQL, pois suporta operações CRUD, embora o processador jq nunca substitua sua entrada. O jq também pode manipular fluxos de entidades JSON.

Dois outros critérios que você pode considerar na avaliação de uma linguagem de consulta orientada a JSON são:

  • suporta expressões regulares? (o jq 1.5 possui suporte abrangente para regex PCRE)
  • é Turing completo? (Sim)
pico
fonte
8

Defiant.js também parece bem legal, aqui está um exemplo simples:

var obj = {
        "car": [
            {"id": 10, "color": "silver", "name": "Volvo"},
            {"id": 11, "color": "red",    "name": "Saab"},
            {"id": 12, "color": "red",    "name": "Peugeot"},
            {"id": 13, "color": "yellow", "name": "Porsche"}
        ],
        "bike": [
            {"id": 20, "color": "black", "name": "Cannondale"},
            {"id": 21, "color": "red",   "name": "Shimano"}
        ]
    },
    search = JSON.search(obj, '//car[color="yellow"]/name');

console.log( search );
// ["Porsche"]

var reds = JSON.search(obj, '//*[color="red"]');

for (var i=0; i<reds.length; i++) {
    console.log( reds[i].name );
}
// Saab
// Peugeot
// Shimano
Epoc
fonte
Infelizmente, não está publicado no npm no momento e requer instalação manual ...
Andrew Mao
7

Jsel é incrível e é baseado em um mecanismo XPath real. Permite criar expressões XPath para encontrar qualquer tipo de dados JavaScript, não apenas objetos (cadeias de caracteres também).

Você pode criar esquemas e mapeamentos personalizados para fornecer controle completo sobre como seus dados são acessíveis pelo mecanismo XPath. Um esquema é uma maneira de definir como elementos, filhos, atributos e valores de nós são definidos em seus dados. Então você pode criar suas próprias expressões para se adequar.

Como você tinha uma variável chamada dataque continha o JSON da pergunta, você poderia usar o jsel para escrever:

jsel(data).select("//*[@id=3]")

Isso retornará qualquer nó com um idatributo 3. Um atributo é qualquer valor primitivo (string, número, data, regex) dentro de um objeto.

Todos
fonte
6

O ObjectPath é uma linguagem de consulta semelhante ao XPath ou JSONPath, mas muito mais poderosa graças aos cálculos aritméticos incorporados, mecanismos de comparação e funções internas. Veja a sintaxe:

Encontre na loja todos os sapatos de cor vermelha e preço menor que 50

$ .. sapatos. * [a cor é "vermelha" e o preço <50]

Ela Bednarek
fonte
Eu gosto do primeiro exemplo no site e é ótimo que o ObjectPath possa ser executado em um modo interativo, semelhante ao shell, mas o que estou procurando é usar o ObjectPath em um script Python. Você pode me indicar um exemplo mostrando como usar o ObjectPath como uma biblioteca? Não consigo encontrar nada parecido no site.
Piokuc
Por favor, veja a seção sobre o uso do Python no github . Adicionaremos isso ao site - é realmente difícil de encontrar no momento. Se precisar de mais ajuda, você pode postar uma pergunta no grupo do Google .
precisa
Obrigado, Ela, os exemplos adicionados na página do github são exatamente o que era necessário.
Piokuc
4

@Naftule - com "defiant.js", é possível consultar uma estrutura JSON com expressões XPath. Confira este avaliador para ter uma idéia de como ele funciona:

http://www.defiantjs.com/#xpath_evaluator

Diferentemente do JSONPath, "defiant.js" fornece o suporte em grande escala da sintaxe da consulta - do XPath nas estruturas JSON.

O código fonte do defiant.js pode ser encontrado aqui:
https://github.com/hbi99/defiant.js

Hakan Bilgin
fonte
3

O JMESPath parece ser muito popular hoje em dia (a partir de 2020) e aborda vários problemas com o JSONPath. Está disponível para vários idiomas.

jlh
fonte
1

Se você é como eu e apenas deseja fazer pesquisas baseadas em caminhos, mas não se importa com o XPath real, o lodash's _.get()pode funcionar. Exemplo de documentação do lodash:

var object = { 'a': [{ 'b': { 'c': 3 } }] };

_.get(object, 'a[0].b.c');
// → 3

_.get(object, ['a', '0', 'b', 'c']);
// → 3

_.get(object, 'a.b.c', 'default');
// → 'default'
adittes
fonte
Infelizmente, essa função pode retornar apenas um único resultado, não suporta buscar uma matriz de itens correspondentes, que é onde as outras bibliotecas brilham.
Simon East