Czy istnieje odpowiednik JSON dla XQuery / XPath?

221

Podczas wyszukiwania elementów w złożonych tablicach i skrótach JSON, takich jak:

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

Czy istnieje jakiś język zapytań, za pomocą którego można znaleźć element in [0].objects where id = 3?

Naftuli Kay
źródło
nie, chyba że je stworzysz. Pozostaw zapytanie do serwera i użyj REST, aby uzyskać tylko potrzebne dane.
zzzzBov,
5
+1 dobry pomysł. Napiszę to jutro…
2
Nie XPath, ale uważam, że JLinq jest całkiem niezły (co sprawia, że ​​kod można czytać jak in(...).where(...).select(...)): hugoware.net/Projects/jLinq .
pimvdb,
4
Jest to frustrujące, ponieważ istnieje wiele bibliotek, ale nic nie zbliża się do powszechnie przyjętego standardu. Mamy bibliotekę używaną przez strony trzecie, dlatego musimy podać język zapytań, który jest powszechnie znany i używany.
David Thielen,
1
Jasne, możesz użyć jsel - github.com/dragonworx/jsel - pod warunkiem, że masz zmienną datazawierającą obiekt JSON, napisałbyś: jsel(data).select("//*[@id=3]")i zwróciłby obiekt zawierający klucz id z 3.
Ali

Odpowiedzi:

122

Tak, nazywa się JSONPath . Źródło znajduje się teraz na GitHub .

Jest również zintegrowany z DOJO .

Mike Christensen
źródło
3
Odpowiedź Briana sugeruje, że moduł jsonQuery powinien być używany zamiast modułu jsonPath w dojo.
hugomg,
5
Jak solidne to jest? I nie mogę znaleźć wersji Java lub C #, która jest dla nas zabójcą transakcji.
David Thielen,
2
Strona, do której prowadzi link, zapewnia obsługę Javascript i PHP. Jeśli potrzebujesz implementacji Java, jest tu jedna: code.google.com/p/json-path
Matthias Ronge
2
Powinienem wspomnieć, że JSONPath nie jest oparty na formalnym semantycznym XPath. JSONiq może być lepszą opcją.
wcandillon
1
@Paramaeleon To działa świetnie. Nawiasem mówiąc, projekt został migrowany do GitHub . Mike może chcieć dodać to do odpowiedzi, ponieważ ludzie wciąż o tym komentują.
Franklin Yu
21

Myślę, że JSONQuery jest nadzbiorem JSONPath i dlatego zastępuje go w dojo . Jest też RQL .

Z dokumentacji Dojo:

JSONQuery jest rozszerzoną wersją JSONPath z dodatkowymi funkcjami bezpieczeństwa, łatwości użytkowania i kompleksowym zestawem narzędzi do zapytań o dane, w tym filtrowaniem, wyszukiwaniem rekurencyjnym, sortowaniem, mapowaniem, wyborem zakresu i elastycznymi wyrażeniami z porównaniami ciągów znaków wieloznacznych i różnymi operatorami.

JSONselect ma inny punkt widzenia na pytanie (podobny do selektora CSS, a nie XPath) i ma implementację JavaScript .

Brian Clozel
źródło
4
Łącze github JSONQuery wydaje się być martwe. JSONSelect ma teraz także wersję JavaScript.
Henrik Aasted Sørensen,
19

Inne znane mi alternatywy

  1. Specyfikacja JSONiq , która określa dwa podtypy języków: jeden, który ukrywa szczegóły XML i zapewnia składnię podobną do JS, oraz jeden, który wzbogaca składnię XQuery o konstruktory JSON i tym podobne. Zorba wdraża JSONiq.
  2. Corona , oparta na MarkLogic, zapewnia interfejs REST do przechowywania, zarządzania i wyszukiwania treści XML, JSON, tekstowych i binarnych.
  3. MarkLogic 6 i nowsze zapewniają podobny interfejs REST jak Corona po wyjęciu z pudełka.
  4. MarkLogic 8 i nowsze wersje wspierają JSON w natywnym środowisku XQuery i JavaScript po stronie serwera. Możesz na nim zastosować XPath.

HTH.

grtjn
źródło
3
Istnieje teraz implementacja JSONiq: Zorba 2.6 oficjalnie ją obsługuje.
Ghislain Fourny
Uwaga: MarkLogic przechowuje JSON natywnie od wersji 8 i umożliwia bezpośrednie stosowanie XPath na nim.
grtjn
18

Aby podsumować niektóre z bieżących opcji przeglądania / filtrowania danych JSON i podać kilka przykładów składni ...

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

  • json: select () (zainspirowany bardziej przez selektory CSS)
    .automobiles .maker:val("Honda") .model

  • JSONPath (zainspirowany bardziej przez XPath)
    $.automobiles[?(@.maker='Honda')].model

Myślę, że JSPath wygląda najlepiej, więc spróbuję zintegrować go z moją aplikacją AngularJS + CakePHP.

(Oryginalnie zamieściłem tę odpowiedź w innym wątku, ale pomyślałem, że tutaj też się przyda.)

Simon East
źródło
Świetne podsumowanie i przykłady, również ze względu na wzmiankę o inspiracji znalezionej w selektorach CSS lub XPath.
Jochem Schulenklopper
13

Spróbuj użyć JSPath

JSPath to język specyficzny dla domeny (DSL), który umożliwia nawigację i wyszukiwanie danych w dokumentach JSON. Korzystając z JSPath, możesz wybierać elementy JSON w celu odzyskania zawartych w nich danych.

JSPath dla JSON jak XPath dla XML.

Jest mocno zoptymalizowany zarówno dla Node.js, jak i nowoczesnych przeglądarek.

dfilatov
źródło
9

XQuery może być użyty do zapytania JSON, pod warunkiem, że procesor oferuje obsługę JSON. Jest to prosty przykład, w jaki sposób można użyć BaseX do znajdowania obiektów o „id” = 1:

json:parse('[
    { "id": 1, "name": "One", "objects": [
        { "id": 1, "name": "Response 1", "objects": [ "etc." ] }
    ]}
]')//value[.//id = 1]
Christian Grün
źródło
(6 lat później) Saxon uruchomi XQuery 3.1, który wysyła zapytania do JSON. Moje saksońskie doświadczenie polega na korzystaniu z pliku jar uruchamianego przez Javę. Istnieje moduł węzła o nazwie saxon-java, ale nie jestem pewien, jak to działa w / json. I jest jeszcze jedna nowa rzecz z Saxonica o nazwie Saxon-JS.
Charles Ross
9

Czy istnieje jakiś język zapytań ...

JQ definiuje J SON q język uery, który jest bardzo podobny do JSONPath - patrz https://github.com/stedolan/jq/wiki/For-JSONPath-users

... [który] mogę użyć do znalezienia przedmiotu w [0] .obiekty gdzie id = 3?

Zakładam, że oznacza to: znajdź wszystkie obiekty JSON pod określonym kluczem o id == 3, bez względu na to, gdzie może być ten obiekt. Odpowiednie zapytanie jq byłoby:

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

gdzie „|” jest operatorem potoku (jak w potoku powłoki poleceń) i gdzie segment „.. | obiekty” odpowiada „bez względu na to, gdzie może być ten obiekt”.

Podstawy jq są w dużej mierze oczywiste, intuicyjne lub przynajmniej dość proste, a większość pozostałych jest łatwa do zrozumienia, jeśli w ogóle znasz potoki poleceń. Często zadawane pytania dotyczące jq zawierają wskaźniki do samouczków i tym podobne.

jq jest również jak SQL, ponieważ obsługuje operacje CRUD, chociaż procesor jq nigdy nie zastępuje danych wejściowych. jq może również obsługiwać strumienie jednostek JSON.

Dwa inne kryteria, które warto rozważyć przy ocenie języka zapytań JSON, to:

  • czy obsługuje wyrażenia regularne? (jq 1.5 ma kompleksową obsługę wyrażeń regularnych PCRE)
  • czy Turing jest kompletny? (tak)
szczyt
źródło
8

Defiant.js wygląda również całkiem fajnie, oto prosty przykład:

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
źródło
Niestety, nie opublikowany w tej chwili na NPM i wymaga ręcznej instalacji ...
Andrew Mao
7

Jsel jest niesamowity i opiera się na prawdziwym silniku XPath. Umożliwia tworzenie wyrażeń XPath w celu znalezienia dowolnego rodzaju danych JavaScript, nie tylko obiektów (również łańcuchów).

Możesz tworzyć niestandardowe schematy i odwzorowania, aby dać ci pełną kontrolę nad tym, jak twoje dane są dostępne do przejścia przez silnik XPath. Schemat to sposób definiowania sposobu definiowania elementów, elementów podrzędnych, atrybutów i wartości węzłów w danych. Następnie możesz stworzyć własne wyrażenia, które będą pasować.

Biorąc pod uwagę, że masz zmienną o nazwie dataJSON z pytania, możesz użyć jsel do napisania:

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

Zwróci to dowolny węzeł z idatrybutem 3. Atrybut to dowolna pierwotna wartość (ciąg, liczba, data, wyrażenie regularne) w obiekcie.

Ali
źródło
6

ObjectPath to język zapytań podobny do XPath lub JSONPath, ale o wiele bardziej wydajny dzięki wbudowanym obliczeniom arytmetycznym, mechanizmom porównywania i wbudowanym funkcjom. Zobacz składnię:

Znajdź w sklepie wszystkie buty w kolorze czerwonym i cenie mniejszej niż 50

$ .. buty. * [kolor jest „czerwony”, a cena <50]

Ela Bednarek
źródło
Podoba mi się pierwszy przykład na stronie internetowej i świetnie, że ObjectPath można uruchamiać w interaktywnym trybie przypominającym powłokę, ale to, czego szukam, to użycie ObjectPath w skrypcie Python. Czy możesz wskazać mi przykład pokazujący, jak używać ObjectPath jako biblioteki? Nie mogę znaleźć czegoś takiego na stronie.
piokuc
Zobacz sekcję dotyczącą używania Pythona na github . Dodamy to do strony internetowej - w tej chwili naprawdę trudno ją znaleźć. Jeśli potrzebujesz dalszej pomocy, możesz opublikować pytanie w grupie Google .
Ela Bednarek
Dziękuję, Ela, przykłady dodane na stronie github są dokładnie tym, czego potrzebowaliśmy.
piokuc
4

@Naftule - za pomocą „defiant.js” możliwe jest zapytanie o strukturę JSON za pomocą wyrażeń XPath. Sprawdź tego oceniającego, aby dowiedzieć się, jak to działa:

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

W przeciwieństwie do JSONPath, „defiant.js” zapewnia pełną obsługę składni zapytania - XPath w strukturach JSON.

Kod źródłowy defiant.js można znaleźć tutaj:
https://github.com/hbi99/defiant.js

Hakan Bilgin
źródło
3

JMESPath wydaje się obecnie bardzo popularny (od 2020 r.) I rozwiązuje szereg problemów z JSONPath. Jest dostępny dla wielu języków.

jlh
źródło
1

Jeśli jesteś podobny do mnie i chcesz po prostu przeglądać ścieżki, ale nie przejmuj się prawdziwym XPath, lodash _.get()może działać. Przykład z dokumentów 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'
przyznaje
źródło
Niestety, funkcja ta może zwrócić tylko jeden wynik, nie obsługuje pobierania tablicy pasujących elementów, i tam właśnie świecą inne biblioteki.
Simon East