Introduksjon til JsonPath

1. Oversikt

En av fordelene med XML er tilgjengeligheten av behandling - inkludert XPath - som er definert som en W3C-standard. For JSON har et lignende verktøy som heter JSONPath dukket opp.

Denne artikkelen vil gi en introduksjon til Jayway JsonPath, en Java-implementering av JSONPath-spesifikasjonen. Den beskriver oppsett, syntaks, vanlige APIer og en demonstrasjon av brukssaker.

2. Oppsett

For å bruke JsonPath, trenger vi bare å inkludere en avhengighet i Maven pom:

 com.jayway.jsonpath json-path 2.4.0 

3. Syntaks

Følgende JSON-struktur vil bli brukt i denne delen for å demonstrere syntaksen og API-ene til JsonPath:

{"tool": {"jsonpath": {"creator": {"name": "Jayway Inc.", "location": ["Malmo", "San Francisco", "Helsingborg"]}}, "book ": [{" title ":" Begynner JSON "," pris ": 49,99}, {" title ":" JSON på jobben "," pris ": 29,99}]}

3.1. Notasjon

JsonPath bruker spesiell notasjon for å representere noder og deres forbindelser til tilstøtende noder i en JsonPath-bane. Det er to stiler av notasjon, nemlig prikk og parentes.

Begge følgende baner refererer til den samme noden fra det ovennevnte JSON-dokumentet, som er det tredje elementet i plassering innen skaperen node, det er et barn av jsonpath gjenstand som tilhører verktøy under rotnoden.

Med punktnotasjon:

$ .tool.jsonpath.creator.location [2]

Med brakettnotasjon:

$ ['tool'] ['jsonpath'] ['creator'] ['location'] [2]

Dollartegnet ($) representerer rotmedlemsobjektet.

3.2. Operatører

Vi har flere nyttige operatører i JsonPath:

Rotknutepunkt ($): Dette symbolet betegner rotelementet til en JSON-struktur uansett om det er et objekt eller en matrise. Brukseksemplene ble inkludert i forrige underavsnitt.

Nåværende node (@): Representerer noden som behandles, brukes mest som en del av inngangsuttrykk for predikater. Anta at vi har å gjøre med bok array i det ovennevnte JSON-dokumentet, uttrykket bok [? (@. pris == 49,99)] refererer til den første bok i den matrisen.

Jokertegn (*): Uttrykker alle elementene innenfor det angitte omfanget. For eksempel, bok[*] indikerer alle noder inne i bok array.

3.3. Funksjoner og filtre

JsonPath har også funksjoner som kan brukes til slutten av en bane for å syntetisere stiens utgangsuttrykk: min (), maks (), avg (), stddev (), lengde().

Til slutt - vi har filtre; Dette er boolske uttrykk for å begrense returnerte lister med noder til bare de som anropsmetoder trenger.

Noen få eksempler er likhet (==), matching av regulært uttrykk (=~), inkludering (i), sjekk for tomhet (tømme). Filtre brukes hovedsakelig til predikater.

For en fullstendig liste og detaljerte forklaringer på forskjellige operatører, funksjoner og filtre, se JsonPath GitHub-prosjektet.

4. Operasjoner

Før vi går i drift, en rask side-note - denne delen bruker JSON-eksempelstrukturen vi definerte tidligere.

4.1. Tilgang til dokumenter

JsonPath har en praktisk måte å få tilgang til JSON-dokumenter, som er gjennom statisk lese APIer:

 T JsonPath.read (String jsonString, String jsonPath, Predicate ... filtre);

De lese APIer kan fungere med statiske flytende APIer for å gi mer fleksibilitet:

 T JsonPath.parse (String jsonString) .les (String jsonPath, Predicate ... filters);

Andre overbelastede varianter av lese kan brukes til forskjellige typer JSON-kilder, inkludert Gjenstand, InputStream, URL, og Fil.

For å gjøre ting enkle inkluderer ikke testen for denne delen predikater i parameterlisten (tom varargs); predikater vil bli diskutert i senere underavsnitt.

La oss starte med å definere to prøvebaner å jobbe med:

String jsonpathCreatorNamePath = "$ ['tool'] ['jsonpath'] ['creator'] ['name']"; String jsonpathCreatorLocationPath = "$ ['tool'] ['jsonpath'] ['creator'] ['location'] [*]";

Deretter vil vi lage en DocumentContext objekt ved å analysere den gitte JSON-kilden jsonDataSourceString. Det nyopprettede objektet vil da bli brukt til å lese innhold ved å bruke stiene som er definert ovenfor:

DocumentContext jsonContext = JsonPath.parse (jsonDataSourceString); Streng jsonpathCreatorName = jsonContext.read (jsonpathCreatorNamePath); Liste jsonpathCreatorLocation = jsonContext.read (jsonpathCreatorLocationPath);

Den første lese API returnerer en String inneholder navnet på JsonPath-skaperen, mens den andre returnerer en liste over adressene. Og vi bruker JUnit Påstå API for å bekrefte at metodene fungerer som forventet:

assertEquals ("Jayway Inc.", jsonpathCreatorName); assertThat (jsonpathCreatorLocation.toString (), inneholderString ("Malmo")); assertThat (jsonpathCreatorLocation.toString (), inneholderString ("San Francisco")); assertThat (jsonpathCreatorLocation.toString (), inneholderString ("Helsingborg"));

4.2. Predikater

Nå som vi er ferdige med det grunnleggende, la oss definere et nytt JSON-eksempel for å jobbe med og illustrere opprettelse og bruk av predikater:

{"book": [{"title": "Begynnende JSON", "author": "Ben Smith", "price": 49.99}, {"title": "JSON at Work", "author": "Tom Marrs "," price ": 29.99}, {" title ":" Lær JSON på en DAG "," author ":" Acodemy "," price ": 8.99}, {" title ":" JSON: Questions and Answers ", "author": "George Duckett", "price": 6.00}], "price range": {"cheap": 10.00, "medium": 20.00}}

Predikater bestemmer sanne eller falske inngangsverdier for filtre for å begrense returnerte lister til bare samsvarende objekter eller matriser. EN Predikere kan lett integreres i en Filter ved å bruke som argument for sin statiske fabrikkmetode. Det etterspurte innholdet kan deretter leses ut av en JSON-streng ved hjelp av det Filter:

Filter expensiveFilter = Filter.filter (Criteria.where ("pris"). Gt (20.00)); Liste dyrt = JsonPath.parse (jsonDataSourceString) .read ("$ ['book'] [?]", expensiveFilter); predicateUsageAssertionHelper (dyrt);

Vi kan også definere våre tilpassede Predikere og bruke det som et argument for lese API:

Predicate expensivePredicate = new Predicate () {public boolean apply (PredicateContext context) {String value = context.item (Map.class) .get ("price"). ToString (); returner Float.valueOf (verdi)> 20.00; }}; Liste dyrt = JsonPath.parse (jsonDataSourceString) .read ("$ ['book'] [?]", expensivePredicate); predicateUsageAssertionHelper (dyrt);

Til slutt kan et predikat brukes direkte på lese API uten oppretting av noen objekter, som kalles innebygd predikat:

Liste dyrt = JsonPath.parse (jsonDataSourceString) .read ("$ ['book'] [? (@ ['price']> $ ['price range'] ['medium'])]"); predicateUsageAssertionHelper (dyrt);

Alle de tre av Predikere eksemplene ovenfor er verifisert ved hjelp av følgende påstandshjelpemetode:

private void predicateUsageAssertionHelper (List predicate) {assertThat (predicate.toString (), containString ("Begynnende JSON")); assertThat (predicate.toString (), inneholderString ("JSON at Work")); assertThat (predicate.toString (), ikke (containString ("Lær JSON på en DAG"))); assertThat (predicate.toString (), ikke (containString ("JSON: Spørsmål og svar"))); }

5. Konfigurasjon

5.1. Alternativer

Jayway JsonPath gir flere alternativer for å justere standardkonfigurasjonen:

  • Alternativ.AS_PATH_LIST: Returnerer stier for evalueringstreff i stedet for deres verdier.
  • Alternativ.DEFAULT_PATH_LEAF_TO_NULL: Returnerer null for manglende blader.
  • Alternativ.ALWAYS_RETURN_LIST: Returnerer en liste selv når banen er bestemt.
  • Alternativ.SUPPRESS_EXCEPTIONS: Sikrer at ingen unntak forplanter seg fra stevaluering.
  • Option.REQUIRE_PROPERTIES: Krever egenskaper definert i banen når en ubestemt bane blir evaluert.

Slik gjør du det Alternativ påføres fra bunnen av:

Konfigurasjonskonfigurasjon = Configuration.builder (). Alternativer (alternativ.). Build ();

og hvordan du legger det til en eksisterende konfigurasjon:

Konfigurasjon newConfiguration = configuration.addOptions (alternativ.);

5.2. SPI

JsonPaths standardkonfigurasjon ved hjelp av Alternativ bør være nok for de fleste oppgaver. Imidlertid kan brukere med mer komplekse brukssaker endre atferden til JsonPath i henhold til deres spesifikke krav - ved hjelp av tre forskjellige SPIer:

  • JsonProvider SPI: Lar oss endre måtene JsonPath analyserer og håndterer JSON-dokumenter på
  • MappingProvider SPI: Gjør det mulig å tilpasse bindinger mellom nodeverdier og returnerte objekttyper
  • CacheProvider SPI: Justerer manerer som stier er hurtigbufret, noe som kan bidra til å øke ytelsen

6. Et eksempel på brukstilfeller

Nå som vi har god forståelse av funksjonaliteten som JsonPath kan brukes til - la oss se på et eksempel.

Denne delen illustrerer håndtering av JSON-data returnert fra en webtjeneste - antar at vi har en filminformasjonstjeneste, som returnerer følgende struktur:

[{"id": 1, "title": "Casino Royale", "director": "Martin Campbell", "starring": ["Daniel Craig", "Eva Green"], "desc": "Twenty-first James Bond-film "," utgivelsesdato ": 1163466000000," billettkontor ": 594275385}, {" id ": 2," title ":" Quantum of Solace "," regissør ":" Marc Forster "," med hovedrollen: ["Daniel Craig", "Olga Kurylenko"], "desc": "Twenty-second James Bond movie", "release date": 1225242000000, "box office": 591692078}, {"id": 3, "title" : "Skyfall", "regissør": "Sam Mendes", "starring": ["Daniel Craig", "Naomie Harris"], "desc": "Twenty-third James Bond movie", "release date": 1350954000000, "billettkontor": 1110526981}, {"id": 4, "title": "Spectre", "regissør": "Sam Mendes", "starring": ["Daniel Craig", "Lea Seydoux"], "desc ":" Tjuefjerde James Bond-film "," utgivelsesdato ": 1445821200000," billettkontor ": 879376275}]

Hvor verdien av Utgivelsesdato feltet er varighet siden epoken i millisekunder og billettluke er inntekter fra en film på kino i amerikanske dollar.

Vi skal håndtere fem forskjellige arbeidsscenarier relatert til GET-forespørsler, og antar at ovennevnte JSON-hierarki er hentet ut og lagret i en String variabel navngitt jsonString.

6.1. Få ID-er for objektdata

I dette brukstilfellet ber en klient detaljert informasjon om en bestemt film ved å gi serveren nøyaktig id av den. Dette eksemplet viser hvordan serveren ser etter forespurte data før han returnerer til klienten.

Si at vi må finne en plate med id tilsvarer 2. Nedenfor er hvordan prosessen implementeres og testes.

Det første trinnet er å plukke opp riktig dataobjekt:

Objekt dataObject = JsonPath.parse (jsonString) .les ("$ [? (@. Id == 2)]"); Streng dataString = dataObject.toString ();

JUnit Påstå API bekrefter eksistensen av flere felt:

assertThat (dataString, containString ("2")); assertThat (dataString, containString ("Quantum of Solace")); assertThat (dataString, containString ("Twenty-second James Bond movie"));

6.2. Å få filmtittelen gitt hovedrollen

La oss si at vi vil se etter en film med en skuespillerinne i hovedrollen Eva Green. Serveren må returnere tittel av filmen som Eva Green er inkludert i med hovedrollen array.

Den påfølgende testen vil illustrere hvordan du gjør det og validere det returnerte resultatet:

@Test offentlig ugyldig givenStarring_whenRequestingMovieTitle_thenSucceed () {List dataList = JsonPath.parse (jsonString) .read ("$ [? ('Eva Green' i @ ['starring'])]"); String title = (String) dataList.get (0) .get ("title"); assertEquals ("Casino Royale", tittel); }

6.3. Beregning av totalinntekt

Dette scenariet bruker en JsonPath-funksjon som heter lengde() for å finne ut antall filmoppføringer, for å beregne den totale inntekten for alle filmene. Implementeringen og testingen demonstreres som følger:

@Test offentlig ugyldig givenCompleteStructure_whenCalculatingTotalRevenue_thenSucceed () {DocumentContext context = JsonPath.parse (jsonString); int lengde = context.read ("$. lengde ()"); lange inntekter = 0; for (int i = 0; i <lengde; i ++) {inntekt + = context.read ("$ [" + i + "] ['billettkontor']", Long.class); } assertEquals (594275385L + 591692078L + 1110526981L + 879376275L, inntekt); }

6.4. Høyeste inntektsfilm

Denne brukssaken eksemplifiserer bruken av et ikke-standard JsonPath-konfigurasjonsalternativ, nemlig Alternativ.AS_PATH_LIST, for å finne ut filmen med høyest inntekt. De spesifikke trinnene er beskrevet nedenfor.

Først må vi trekke ut en liste over alle filmens billettkontorinntekter, og deretter konvertere den til en matrise for sortering:

DocumentContext context = JsonPath.parse (jsonString); Liste IncomeList = context.read ("$ [*] ['billettkontor']"); Heltall [] incomeArray = incomeList.toArray (nytt Heltall [0]); Arrays.sort (incomeArray);

De høyeste inntekt variabel kan lett hentes fra inntekterArray sortert matrise, og deretter brukt til å finne veien til filmopptaket med høyest inntekt:

int highestRevenue = incomeArray [incomeArray.length - 1]; Configuration pathConfiguration = Configuration.builder (). Alternativer (Option.AS_PATH_LIST) .build (); Liste pathList = JsonPath.using (pathConfiguration) .parse (jsonString) .read ("$ [? (@ ['Kassa'] ==" + høyeste inntekt + ")]");

Basert på den beregnede banen, tittel av den tilsvarende filmen kan bestemmes og returneres:

KartdataRecord = context.read (pathList.get (0)); Streng tittel = dataRecord.get ("tittel");

Hele prosessen bekreftes av Påstå API:

assertEquals ("Skyfall", tittel);

6.5. Siste film av en regissør

Dette eksemplet vil illustrere måten å finne ut den sistnevnte filmen regissert av en regissør som heter Sam Mendes.

Til å begynne med en liste over alle filmene regissert av Sam Mendes er skapt:

DocumentContext context = JsonPath.parse (jsonString); Liste dataList = context.read ("$ [? (@. direktør == 'Sam Mendes')]");

Denne listen brukes til utvinning av utgivelsesdatoer. Disse datoene vil bli lagret i en matrise og deretter sortert:

List dateList = new ArrayList (); for (Map item: dataList) {Object date = item.get ("release date"); dateList.add (dato); } Lang [] dateArray = dateList.toArray (ny lang [0]); Arrays.sort (dateArray);

De lastestTime variabel, som er det siste elementet i den sorterte matrisen, brukes i kombinasjon med regissør feltets verdi for å bestemme tittel av den etterspurte filmen:

long latestTime = dateArray [dateArray.length - 1]; Liste finalDataList = context.read ("$ [? (@ ['director'] == 'Sam Mendes' && @ ['release date'] ==" + latestTime + ")]"); String title = (String) finalDataList.get (0) .get ("title");

Følgende påstand beviste at alt fungerer som forventet:

assertEquals ("Spectre", tittel);

7. Konklusjon

Denne opplæringen har dekket grunnleggende funksjoner i Jayway JsonPath - et kraftig verktøy for å krysse og analysere JSON-dokumenter.

Selv om JsonPath har noen ulemper, for eksempel mangel på operatører for å nå foreldre- eller søskenoder, kan det være svært nyttig i mange scenarier.

Implementeringen av alle disse eksemplene og kodebiter finner du i a GitHub-prosjekt.


$config[zx-auto] not found$config[zx-overlay] not found