Uvod u JsonPath
1. Pregled
Jedna od prednosti XML-a je dostupnost obrade - uključujući XPath - koja je definirana kao W3C standard. Za JSON se pojavio sličan alat nazvan JSONPath.
Ovaj će članak dati članak uvod u Jayway JsonPath, Java implementacija JSONPath specifikacije. Opisuje postavljanje, sintaksu, uobičajene API-je i demonstraciju slučajeva korištenja.
2. Postavljanje
Da bismo koristili JsonPath, jednostavno moramo uključiti ovisnost u Maven pom:
com.jayway.jsonpath json-path 2.4.0
3. Sintaksa
Sljedeća JSON struktura koristit će se u ovom odjeljku za demonstraciju sintakse i API-ja JsonPath:
{"tool": {"jsonpath": {"creator": {"name": "Jayway Inc.", "location": ["Malmo", "San Francisco", "Helsingborg"]}}}, "knjiga ": [{" title ":" Beginning JSON "," price ": 49.99}, {" title ":" JSON na poslu "," price ": 29.99}]}
3.1. Notacija
JsonPath koristi posebnu notaciju za predstavljanje čvorova i njihovih veza sa susjednim čvorovima u JsonPath stazi. Postoje dva stila zapisa, naime točka i zagrada.
Oba se sljedeća puta odnose na isti čvor iz gornjeg JSON dokumenta, koji je treći element u mjesto polje od stvoritelj čvor, koji je podređen sustavu jsonpath objekt koji pripada alat ispod korijenskog čvora.
S oznakom točke:
$ .tool.jsonpath.creator.location [2]
S oznakom zagrade:
$ ['alat'] ['jsonpath'] ['kreator'] ['lokacija'] [2]
Znak dolara ($) predstavlja objekt člana korijena.
3.2. Operateri
U JsonPathu imamo nekoliko korisnih operatora:
Korijenski čvor ($): Ovaj simbol označava korijenski član JSON strukture bez obzira na to je li riječ o objektu ili nizu. Primjeri njegove uporabe uključeni su u prethodni pododjeljak.
Trenutni čvor (@): Predstavlja čvor koji se obrađuje, uglavnom se koristi kao dio ulaznih izraza za predikate. Pretpostavimo da imamo posla knjiga niz u gornjem JSON dokumentu, izraz knjiga [? (@. cijena == 49,99)] odnosi se na prvu knjiga u tom nizu.
Zamjenski znak (*): Izražava sve elemente unutar navedenog opsega. Na primjer, knjiga[*] označava sve čvorove unutar a knjiga niz.
3.3. Funkcije i filtri
JsonPath također ima funkcije koje se mogu koristiti do kraja puta za sintezu izlaznih izraza te staze: min (), maks. (), prosj (), stddev (), duljina ().
Napokon - imamo filtere; ovo su logički izrazi za ograničavanje vraćenih popisa čvorova samo na one koji trebaju metode pozivanja.
Nekoliko primjera su jednakost (==), podudaranje regularnog izraza (=~), uključenje, Ubrajanje (u), provjerite prazninu (prazan). Filteri se uglavnom koriste za predikate.
Potpuni popis i detaljna objašnjenja različitih operatora, funkcija i filtara potražite u projektu JsonPath GitHub.
4. Operacije
Prije nego započnemo s operacijama, kratka napomena - ovaj odjeljak koristi strukturu primjera JSON-a koju smo prethodno definirali.
4.1. Pristup dokumentima
JsonPath ima prikladan način pristupa JSON dokumentima, koji je putem statike čitati Apis:
T JsonPath.read (String jsonString, String jsonPath, Predicate ... filtri);
The čitati API-ji mogu raditi sa statičnim fluidnim API-ima kako bi pružili veću fleksibilnost:
T JsonPath.parse (String jsonString) .read (String jsonPath, Predicate ... filtri);
Ostale preopterećene inačice čitati mogu se koristiti za različite vrste JSON izvora, uključujući Objekt, InputStream, URL, i Datoteka.
Da pojednostavnimo stvari, test za ovaj dio ne uključuje predikate na popisu parametara (prazno varargi); predikati bit će razmatrano u sljedećim pododjeljcima.
Počnimo s definiranjem dva uzorka putova na kojima ćemo raditi:
Niz jsonpathCreatorNamePath = "$ ['tool'] ['jsonpath'] ['creator'] ['name']"; Niz jsonpathCreatorLocationPath = "$ ['tool'] ['jsonpath'] ['creator'] ['location'] [*]";
Dalje ćemo stvoriti DocumentContext objekt raščlanjivanjem datog JSON izvora jsonDataSourceString. Novostvoreni objekt tada će se koristiti za čitanje sadržaja koristeći gore definirane staze:
DocumentContext jsonContext = JsonPath.parse (jsonDataSourceString); Niz jsonpathCreatorName = jsonContext.read (jsonpathCreatorNamePath); Popis jsonpathCreatorLocation = jsonContext.read (jsonpathCreatorLocationPath);
Prvi čitati API vraća a Niz koji sadrži ime kreatora JsonPath, dok drugi vraća popis njegovih adresa. I koristit ćemo JUnit Tvrditi API za potvrdu rada metoda kako se očekivalo:
assertEquals ("Jayway Inc.", jsonpathCreatorName); assertThat (jsonpathCreatorLocation.toString (), containsString ("Malmo")); assertThat (jsonpathCreatorLocation.toString (), containsString ("San Francisco")); assertThat (jsonpathCreatorLocation.toString (), containsString ("Helsingborg"));
4.2. Predikati
Sad kad smo završili s osnovama, definirajmo novi JSON primjer na kojem ćemo raditi i ilustrirati stvaranje i upotrebu predikata:
{"book": [{"title": "Beginning JSON", "author": "Ben Smith", "price": 49.99}, {"title": "JSON at Work", "author": "Tom Marrs "," price ": 29,99}, {" title ":" Learn JSON in a DAY "," author ":" Acodemy "," price ": 8.99}, {" title ":" JSON: Pitanja i odgovori ", "autor": "George Duckett", "cijena": 6,00}], "raspon cijena": {"jeftino": 10,00, "srednje": 20,00}}
Predikati određuju istinite ili lažne ulazne vrijednosti za filtre kako bi suzili vraćene popise samo na podudarne objekte ili nizove. A Predikat može se lako integrirati u filtar uporabom kao argumenta za njegovu statičku tvorničku metodu. Zatraženi sadržaj se tada može pročitati iz JSON niza filtar:
Filtriraj skupiFilter = Filter.filter (Criteria.where ("cijena"). Gt (20.00)); Popis
Možemo također definirati naše prilagođene Predikat i koristiti ga kao argument za čitati API:
Predikat skupoPredicate = novi Predikat () {javna logička primjena (kontekst PredicateContext) {Vrijednost niza = context.item (Map.class) .get ("cijena"). ToString (); return Float.valueOf (value)> 20,00; }}; Popis
Konačno, predikat se može izravno primijeniti na čitati API bez stvaranja bilo kakvih objekata, koji se naziva inline predikat:
Popis
Sve tri Predikat gornji primjeri se provjeravaju pomoću sljedeće metode pomoćnog utvrđivanja:
private void predicateUsageAssertionHelper (navesti predikat) {assertThat (predicate.toString (), containsString ("Beginning JSON")); assertThat (preicate.toString (), containsString ("JSON na poslu")); assertThat (preicate.toString (), ne (containsString ("Naučite JSON u DANU"))); assertThat (preicate.toString (), ne (containsString ("JSON: Pitanja i odgovori"))); }
5. Konfiguracija
5.1. Opcije
Jayway JsonPath nudi nekoliko mogućnosti za podešavanje zadane konfiguracije:
- Opcija.AS_PATH_LIST: Vraća staze pogodaka za procjenu umjesto njihovih vrijednosti.
- Opcija.DEFAULT_PATH_LEAF_TO_NULL: Vraća nulu za nedostajuće lišće.
- Opcija.ALWAYS_RETURN_LIST: Vraća popis čak i kad je put definitivan.
- Opcija.SUPPRESS_EXCEPTIONS: Osigurava da se iz procjene putanje ne šire izuzeci.
- Opcija.REQUIRE_SVOJSTVA: Zahtijeva svojstva definirana u putu kada se procjenjuje neodređeni put.
Evo kako Opcija primjenjuje se od nule:
Konfiguracija konfiguracije = Configuration.builder (). Options (Option.). Build ();
i kako ga dodati u postojeću konfiguraciju:
Konfiguracija newConfiguration = configuration.addOptions (opcija);
5.2. SPI
Zadana konfiguracija JsonPath-a uz pomoć Opcija trebao biti dovoljan za većinu zadataka. Međutim, korisnici sa složenijim slučajevima upotrebe mogu izmijeniti ponašanje JsonPath-a u skladu sa svojim specifičnim zahtjevima - koristeći tri različita SPI-a:
- JsonProvider SPI: Omogućuje nam promjenu načina na koji JsonPath raščlanjuje i obrađuje JSON dokumente
- MappingProvider SPI: Omogućava prilagodbu veza između vrijednosti čvora i vraćenih tipova objekata
- CacheProvider SPI: podešava načine predmemoriranja staza, što može pomoći u povećanju performansi
6. Primjer slučajeva korištenja
Sad kad dobro razumijemo funkcionalnost za koju se JsonPath može koristiti - pogledajmo primjer.
Ovaj odjeljak ilustrira rad s JSON podacima vraćenim s web usluge - pretpostavimo da imamo uslugu informacija o filmovima koja vraća sljedeću strukturu:
[{"id": 1, "title": "Casino Royale", "director": "Martin Campbell", "glumi": ["Daniel Craig", "Eva Green"], "desc": "Dvadeset i prvi Film o Jamesu Bondu "," datum izlaska ": 1163466000000," blagajna ": 594275385}, {" id ": 2," title ":" Quantum of Solace "," director ":" Marc Forster "," starring ": ["Daniel Craig", "Olga Kurylenko"], "desc": "Dvadeset drugi film o Jamesu Bondu", "datum izlaska": 1225242000000, "blagajna": 591692078}, {"id": 3, "naslov" : "Skyfall", "director": "Sam Mendes", "glumi": ["Daniel Craig", "Naomie Harris"], "desc": "Dvadeset i treći film o Jamesu Bondu", "datum izlaska": 1350954000000, "blagajna": 1110526981}, {"id": 4, "title": "Spectre", "director": "Sam Mendes", "starring": ["Daniel Craig", "Lea Seydoux"], "desc ":" Dvadeset i četvrti film o Jamesu Bondu "," datum izlaska ": 1445821200000," blagajna ": 879376275}]
Gdje je vrijednost Datum izlaska polje je trajanje od epohe u milisekundama i blagajna je prihod filma u kinu u američkim dolarima.
Obrađivat ćemo pet različitih radnih scenarija povezanih s GET zahtjevima, pretpostavljajući da je gornja JSON hijerarhija izvučena i pohranjena u Niz varijabla imenovana jsonString.
6.1. Dobivanje podataka o objektima s obzirom na ID-ove
U ovom slučaju upotrebe, klijent zahtijeva detaljne informacije o određenom filmu dajući poslužitelju točne podatke iskaznica onog. Ovaj primjer pokazuje kako poslužitelj traži tražene podatke prije vraćanja klijentu.
Recimo da moramo pronaći zapis s iskaznica jednak 2. Ispod je prikazano kako se postupak provodi i testira.
Prvi korak je odabrati točan objekt podataka:
Object dataObject = JsonPath.parse (jsonString) .read ("$ [? (@. Id == 2)]"); Niz dataString = dataObject.toString ();
JUnit Tvrditi API potvrđuje postojanje nekoliko polja:
assertThat (dataString, containsString ("2")); assertThat (dataString, containsString ("Quantum of Solace")); assertThat (dataString, containsString ("Dvadeset drugi film o Jamesu Bondu"));
6.2. Dobivanje naslova filma s obzirom na glavnu ulogu
Recimo da želimo potražiti film u kojem glumi glumica zvana Eva Green. Poslužitelj se mora vratiti titula filma koji Eva Green je uključen u glumi niz.
Sljedeći test ilustrirat će kako to učiniti i potvrditi vraćeni rezultat:
@Test javna praznina givenStarring_whenRequestingMovieTitle_thenSucceed () {Popis
6.3. Izračun ukupnog prihoda
Ovaj scenarij koristi funkciju JsonPath koja se naziva duljina () da biste izračunali broj filmskih zapisa, izračunali ukupni prihod svih filmova. Implementacija i testiranje prikazani su na sljedeći način:
@Test javna praznina givenCompleteStructure_whenCalculatingTotalRevenue_thenSucceed () {DocumentContext context = JsonPath.parse (jsonString); int dužina = context.read ("$. length ()"); dugi prihod = 0; for (int i = 0; i <length; i ++) {prihod + = context.read ("$ [" + i + "] ['blagajna']", Long.class); } assertEquals (594275385L + 591692078L + 1110526981L + 879376275L, prihod); }
6.4. Film s najvećim prihodom
Ovaj slučaj upotrebe ilustrira upotrebu ne-zadane opcije konfiguracije JsonPath, naime Opcija.AS_PATH_LIST, kako biste saznali film s najvećim prihodom. Konkretni koraci opisani su u nastavku.
Prvo moramo izdvojiti popis prihoda od blagajne svih filmova, a zatim ga pretvoriti u niz za sortiranje:
DocumentContext context = JsonPath.parse (jsonString); Popis prihodaList = context.read ("$ [*] ['blagajna']"); Integer [] prihodArray = prihodList.toArray (novi Integer [0]); Arrays.sort (prihodArray);
The najviši prihod varijabla se lako može preuzeti s prihodArray sortirani niz, a zatim se koristi za obradu puta do zapisa filma s najvećim prihodom:
int najvišiRevenue = prihodArray [prihodArray.length - 1]; Konfiguracijski putConfiguration = Configuration.builder (). Options (Option.AS_PATH_LIST) .build (); Popis pathList = JsonPath.using (pathConfiguration) .parse (jsonString) .read ("$ [? (@ ['Blagajna'] ==" + najviši prihod + ")]");
Na temelju tog izračunatog puta, titula odgovarajućeg filma može se odrediti i vratiti:
Map dataRecord = context.read (pathList.get (0)); Naslov niza = dataRecord.get ("naslov");
Cijeli postupak potvrđuje Tvrditi API:
assertEquals ("Skyfall", naslov);
6.5. Najnoviji film redatelja
Ovaj primjer ilustrirat će način otkrivanja trajnog filma koji je režirao redatelj Sam Mendes.
Za početak, popis svih filmova u režiji Sam Mendes je stvoreno:
DocumentContext context = JsonPath.parse (jsonString); Popis
Taj se popis koristi za izdvajanje datuma izdanja. Ti će se datumi pohraniti u niz, a zatim sortirati:
Popis dateList = novi ArrayList (); za (Stavka karte: dataList) {Datum objekta = item.get ("datum izdavanja"); dateList.add (datum); } Long [] dateArray = dateList.toArray (novi Long [0]); Nizovi.sort (dateArray);
The najnovije vrijeme varijabla, koja je posljednji element razvrstanog niza, koristi se u kombinaciji s direktor vrijednost polja za određivanje titula traženog filma:
long latestTime = dateArray [dateArray.length - 1]; Popis
Sljedeća je tvrdnja dokazala da sve funkcionira prema očekivanjima:
assertEquals ("Spectre", naslov);
7. Zaključak
Ovaj je vodič obuhvatio temeljne značajke Jaywaya JsonPath - moćnog alata za prelazak i raščlanjivanje JSON dokumenata.
Iako JsonPath ima neke nedostatke, poput nedostatka operatora za dosezanje roditeljskih ili bratskih čvorova, može biti vrlo koristan u mnogim scenarijima.
Provedbu svih ovih primjera i isječaka koda možete pronaći u a GitHub projekt.