Programmering

Java-objektforespørgsler ved hjælp af JXPath

I et nyligt projekt havde jeg brug for en nem måde at krydse Java-objekttræer og udtrække værdier fra objekterne. I stedet for løbende at gennemgå store iterator-hvis-ellers-opsætninger, ville jeg have et værktøj, der gjorde det muligt for mig at sige: "Jeg vil have objektet med id = X, og fra det objekt har jeg brug for værdien af ​​egenskab A." I det væsentlige havde jeg brug for et værktøj til objektforespørgsel.

JXPath er sådan et værktøj til objektforespørgsel. Det er en Apache Commons-komponent, der giver dig mulighed for at forespørge på komplekse objekttræer ved hjælp af det velkendte XPath-ekspressionssprog. Jeg beskæftigede JXPath bredt i mit projekt, og det fremskyndede tingene betydeligt, hvilket gjorde værdiudvindingsalgoritmer til en leg.

Imidlertid er JXPath ikke bredt dokumenteret. Fordi jeg alligevel udforskede komponenten grundigt, besluttede jeg at skrive mine fund ned i en omfattende JXPath-tutorial, som du kan finde på mit websted. Denne artikel er en kortfattet version af denne tutorial, så du hurtigt kan komme i gang med JXPath.

Bemærk: Du kan downloade den ledsagende eksempelkode fra Resources.

Eksempel på model

Til illustration skal vi bruge en simpel model: a Selskab med forskellige afdelinger, hver med forskellige medarbejdere. Her er klassemodellen:

Naturligvis har vi brug for nogle eksempeldata til modellen:

Selskab

Afdeling

Medarbejder (navn, jobtitel, alder)

Acme Inc.

Salg

Johnny, salgsrepræsentant, 45

Sarah, salgsrepræsentant, 33

Magda, kontorassistent, 27

Regnskab

Steve, hovedcontroller, 51

Peter, assistent-controller, 31

Susan, kontorassistent, 27

Med det på plads, lad os begynde at bruge JXPath!

Udførelse af enkle JXPath-forespørgsler

Den mest enkle forespørgsel udtrækker et enkelt objekt fra objekttræet. For eksempel at hente Selskab, brug følgende kode:

JXPathContext context = JXPathContext.newContext (firma); Virksomhed c = (Virksomhed) context.getValue (".");

Den første linje viser oprettelsen af ​​en sammenhæng, udgangspunktet for alle JXPaths XPath-udtryk i objekttræet (kan sammenlignes med rodnode element i et XML-dokument). Den anden linje kode udfører den aktuelle forespørgsel. Siden vores sammenhæng starter på virksomhedsniveau for at hente Selskab objekt bruger vi simpelthen den aktuelle elementvælger '.'.

Brug af prædikater og variabler

En Medarbejder er et barnobjekt af en Afdeling. For at hente Medarbejder benævnt "Johnny" brug følgende kode (Selskab er stadig sammenhængudgangspunkt):

Medarbejder emp = (Medarbejder) context.getValue ("/ departmentList / medarbejdere [name = 'Johnny']");

Grundlæggende lyder koden: "Søg i alle Afdelings fra begyndelsen til Medarbejder objekt, hvoraf navn attribut har værdien 'Johnny'."

Ovenstående kodestykke illustrerer, hvordan man bruger et predikat til at søge på objekter ved hjælp af bestemte værdier. Brug af prædikater kan sammenlignes med brugen af ​​WHERE-klausulen i SQL. Vi kan endda kombinere flere predikater i en forespørgsel:

Medarbejder emp = (Medarbejder) context.getValue ("/ departmentList / medarbejdere [name = 'Susan' og alder = 27]");

Medmindre du bruger en ad-hoc-engangsforespørgsel, er implementering af hardkodede forespørgsler normalt ikke mulig. Det er bedre at definere en genanvendelig forespørgsel, som du derefter kan udføre med forskellige parametre. For at imødekomme parametreret forespørgsel understøtter JXPath variabler i forespørgsler. Ved hjælp af variabler ser koden ovenfor nu sådan ud:

context.getVariables (). erklæreVariable ("navn", "Susan"); context.getVariables (). erklæreVariable ("alder", nyt heltal (27)); Medarbejder emp = (Medarbejder) context.getValue ("/ departmentList / medarbejdere [navn =$ navn og alder =$ alder]");

Iterering over samlinger

JXPath kan levere en iterator over alle objekter, der hentes af en forespørgsel, ligesom iterering af et resultatsæt. Følgende uddrag viser, hvordan du kan gentage det hele Afdelings:

for (Iterator iter = context.iterate ("/ departmentList"); iter.hasNext ();) {Department d = (Department) iter.next (); // ...}

For at hente alle Medarbejders fra alle Afdelings og gentages over dem:

for (Iterator iter = context.iterate ("/ departmentList / medarbejdere"); iter.hasNext ();) {Medarbejder emp = (Medarbejder) iter.next (); // ...}

For at hente alle Medarbejderer ældre end 30 år fra salgsafdelingen:

for (Iterator iter = context.iterate ("/ departmentList [name = 'Salg'] / medarbejdere [alder> 30]"); iter.hasNext ();) {Medarbejder emp = (Medarbejder) iter.next (); // ...}

Og ovenstående eksempel med variabler:

context.getVariables (). erklæreVariable ("afdelingsnavn", "Salg"); context.getVariables (). erklæreVariable ("minalder", nyt heltal (30)); for (Iterator iter = context.iterate ("/ departmentList [name =$ deptName] / ansatte [alder>$ min. alder] "); iter.hasNext ();) {Medarbejder emp = (Medarbejder) iter.next (); // ...}

Disse to sidste kodestykker viser også brugen af ​​flere prædikater inden for en XPath-forespørgsel.

Markører

EN Markør er et JXPath-hjælpeprogram, der repræsenterer en henvisning til placeringen af ​​et objekt i objekttræet. F.eks Markør kan henvise til "den første medarbejder i den anden afdeling." Sammenlignet med objekter hentet direkte fra træet, Markørs tilbyder yderligere funktioner som udførelse af relative forespørgsler igennem relative sammenhænge (mere om dette senere).

Brug af markører

At have en Markør henvise til et objekt i objektet træet er næsten identisk med direkte hentning af objekter:

JXPathContext context = JXPathContext.newContext (firma); Markør empPtr = kontekst.getPointer("/ departmentList [name = 'Salg'] / medarbejdere [alder> 40]"); System.out.println (empPtr); //produktion: / departmentList [1] / medarbejdere [1] System.out.println (((Medarbejder) empPtr.getValue ()) .getnavn ()); //produktion: Johnny

Bemærk, at Markøroutput viser, at en Markør beskriver et objekts placering i stedet for selve objektet. Bemærk også, at det egentlige objekt Markør henviser til kan hentes gennem Markør's getValue () metode.

Markører kan også gentages, som følgende uddrag viser:

for (Iterator iter = kontekst.iteratePointers("/ departmentList [name = 'Salg'] / medarbejdere [alder> 30]"); iter.hasNext ();) {Pointer empPtr = (Pointer) iter.next (); // ...}

Relativ kontekst og relative forespørgsler

Siden en Markør beskriver en placering, kan den bruges som referencepunkt til at navigere gennem hele objekttræet. For at gøre det skal du bruge Markør som rodobjekt (Husk at bruge Selskab objekt til det tidligere?) i en såkaldt relativ kontekst. Fra denne relative kontekst kan du forespørge hele objekttræet ved at udføre relative forespørgsler. Denne avancerede brug af Markørs giver stor fleksibilitet, som eksemplerne nedenfor illustrerer.

For at begynde skal du her se, hvordan du opretter en relativ kontekst:

til (Iterator iter = context.iteratePointers ("/ departmentList [name = 'Salg'] / medarbejdere [alder> 30]"); iter.hasNext ();) {Pointer empPtr = (Pointer) iter.next (); JXPathContext relativeContext = context.getRelativeContext (empPtr); }

I dette kodestykke oprettes en ny relativ kontekst for fortløbende medarbejder henvisninger.

Ved hjælp af den relative kontekst kan XPath-forespørgsler udføres på hele objekttræet for søskende, børn og forældre / bedsteforældreobjekter, som følgende uddrag viser:

// Nuværende medarbejder Medarbejder emp = (Medarbejder) relativeContext.getValue ("."); // Navn på medarbejder String name = (String) relativeContext.getValue ("./ name"); // Navnet på den afdeling, denne medarbejder tilhører (et overordnet objekt) String deptName = (String) relativeContext.getValue ("../ name"); // Navnet på det firma, denne medarbejder tilhører (et 'bedsteforældres' objekt) String compName = (String) relativeContext.getValue ("../../ name"); // Alle medarbejdere i denne medarbejder (søskendeobjekter) til (Iterator empIter = relativeContext.iterate ("../ medarbejdere"); empIter.hasNext ();) {Medarbejderkollega = (Medarbejder) empIter.next (); // ...}

Resumé

JXPath er et ekstremt nyttigt værktøj til at krydse, navigere og forespørge på komplekse objekttræer. Fordi det bruger XPath-ekspressionssprog til sine forespørgsler, er der et stort antal referencematerialer til rådighed, der hjælper dig med at opbygge effektive, men komplekse forespørgsler om genfinding af objekter. Endnu mere fleksibilitet tilføjes ved hjælp af Markørs og relative sammenhænge.

Denne korte artikel skraber kun overfladen af ​​JXPaths muligheder, for en mere detaljeret diskussion med mere avancerede brugseksempler, læs min fulde vejledning.

Bart van Riel har været involveret i Java og den objektorienterede verden i mere end syv år. Han har arbejdet både som udvikler og træner inden for de objektorienterede og Java-felter. Han er i øjeblikket ansat af det globale it-konsulentfirma Capgemini som softwarearkitekt og open source-hovedperson.

Lær mere om dette emne

  • Download kildekoden til denne artikel
  • Tjek den fulde JXPath-tutorial
  • Apache Commons JXPath
  • En god XPath tutorial
  • Gennemse artiklerne i JavaWorld's Udviklingsværktøjer Forskningscenter
  • Hold dig informeret om, hvad der er nyt på JavaWorld! Tilmeld dig vores gratis Enterprise Java nyhedsbrev

Denne historie, "Java-objektforespørgsler ved hjælp af JXPath" blev oprindeligt udgivet af JavaWorld.