Upiti Java objekata pomoću JXPath-a

U nedavnom projektu trebao mi je jednostavan način prelaska Java stabala objekata i izvlačenja vrijednosti iz objekata. Umjesto da neprestano prolazim kroz ogromne postavke iterator-if-else, želio sam alat koji će mi omogućiti da jednostavno kažem: "Želim objekt s id = X, a iz tog objekta trebam vrijednost svojstva A." U osnovi mi je trebao alat za ispitivanje objekata.

JXPath je takav alat za upite objekata. To je komponenta Apache Commons koja vam omogućuje postavljanje upita složenim stablima objekata koristeći dobro poznati jezik izraza XPath. Široko sam upotrijebio JXPath u svom projektu, a on je znatno ubrzao, čineći algoritme za vađenje vrijednosti laganim.

Međutim, JXPath nije široko dokumentiran. Budući da sam ionako detaljno istraživao komponentu, odlučio sam zapisati svoja otkrića u opsežnom JXPath tutorialu koji možete pronaći na mojoj web stranici. Ovaj je članak skraćena verzija tog vodiča za brzi početak rada s JXPathom.

Napomena: Prateći uzorak koda možete preuzeti iz izvora.

Primjer modela

U svrhu ilustracije poslužit ćemo se jednostavnim modelom: tvrtka s raznim odjelima , svaki s različitim zaposlenicima . Evo razrednog modela:

Naravno, trebamo neke uzorke podataka za model:

Društvo

Odjel

Zaposlenik (ime, naziv radnog mjesta, dob)

Acme Inc.

Prodajni

Johnny, prodajni predstavnik, 45

Sarah, prodajna predstavnica, 33

Magda, pomoćnica u uredu, 27

Računovodstvo

Steve, glavni kontrolor, 51

Peter, pomoćni kontrolor, 31

Susan, pomoćnica u uredu, 27

S tim na mjestu, počnimo koristiti JXPath!

Izvršavanje jednostavnih JXPath upita

Najjednostavniji mogući upit izdvaja jedan objekt iz stabla objekata. Na primjer, za dohvaćanje Companyupotrijebite sljedeći kôd:

JXPathContext context = JXPathContext.newContext(company); Company c = (Company)context.getValue(".");

Prvi redak prikazuje stvaranje a context, početne točke za sve JXPath-ove XPath izraze u stablu objekata (usporedivo s rootnodeelementom u XML dokumentu). Drugi redak koda izvršava stvarni upit. Budući da contextzapočinjemo na razini tvrtke, da bismo dohvatili Companyobjekt, jednostavno koristimo selektor trenutnog elementa '.'.

Upotreba predikata i varijabli

An Employeeje podređeni objekt a Department. Da biste dohvatili Employeeimenovanog "Johnny", upotrijebite sljedeći kod ( Companyjoš uvijek contextje početna točka):

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

U osnovi, kôd glasi: "Pretražite sve Departments početka Employeeobjekt čiji je nameatribut vrijednost 'Johnny'."

Gornji isječak koda ilustrira kako koristiti predikat za pretraživanje objekata pomoću određenih vrijednosti. Korištenje predikata usporedivo je s korištenjem klauzule WHERE u SQL-u. Možemo čak kombinirati više predikata u jednom upitu:

Employee emp = (Employee)context.getValue("/departmentList/employees[name='Susan' and age=27]");

Ako ne upotrebljavate ad hoc, jednokratni upit, provođenje upita s kodiranim podacima obično nije izvedivo. Bolje je definirati upit za ponovnu upotrebu koji zatim možete izvršiti s različitim parametrima. Kako bi se prilagodio parametriziranom upitu, JXPath podržava varijable u upitima. Koristeći varijable, gornji kod sada izgleda ovako:

context.getVariables().declareVariable("name", "Susan"); context.getVariables().declareVariable("age", new Integer(27)); Employee emp = (Employee)context.getValue("/departmentList/employees[name=$name and age=$age]");

Iteracija nad zbirkama

JXPath može pružiti iterator za sve objekte dohvaćene upitom, slično poput ponavljanja skupa rezultata. Sljedeći isječak pokazuje kako možete ponavljati sve Departments:

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

Da biste dohvatili sve Employees iz svih Departments i prešli ih:

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

Da biste Employeeiz prodajnog odjela preuzeli sve starije od 30 godina:

for(Iterator iter = context.iterate ("/departmentList[name='Sales']/employees[age>30]"); iter.hasNext();){ Employee emp = (Employee)iter.next(); //... }

I gornji primjer s varijablama:

context.getVariables().declareVariable("deptName", "Sales"); context.getVariables().declareVariable("minAge", new Integer(30)); for(Iterator iter = context.iterate("/departmentList [name=$deptName]/employees[age>$minAge]"); iter.hasNext();){ Employee emp = (Employee)iter.next(); //... }

Ta dva zadnja isječka koda također pokazuju upotrebu nekoliko predikata unutar jednog XPath upita.

Pokazivači

A Pointerje uslužni objekt JXPath koji predstavlja referencu na mjesto objekta u stablu objekata. Na primjer, znak se Pointermože odnositi na "prvog zaposlenika drugog odjela". U usporedbi s objektima dohvaćenim izravno sa stabla, Pointers nude dodatne funkcije poput izvođenja relativnih upita kroz relativni kontekst (o tome kasnije).

Korištenje pokazivača

Upućivanje Pointerna objekt u stablu objekata gotovo je identično izravnom dohvatanju objekata:

JXPathContext context = JXPathContext.newContext(company); Pointer empPtr = context.getPointer("/departmentList[name='Sales']/employees[age>40]"); System.out.println(empPtr); //output: /departmentList[1]/employees[1] System.out.println(((Employee)empPtr.getValue()).getName()); //output: Johnny

Note that the Pointer's output demonstrates that a Pointer describes an object's location, rather than the object itself. Also note that the actual object the Pointer refers to can be retrieved through the Pointer's getValue() method.

Pointers can also be iterated over, as the following snippet demonstrates:

for(Iterator iter = context.iteratePointers("/departmentList[name='Sales'] /employees[age>30]"); iter.hasNext();){ Pointer empPtr = (Pointer)iter.next(); //... }

Relative context and relative queries

Since a Pointer describes a location, it can be used as a reference point for navigating through the entire object tree. To do that, use the Pointer as the root object (Remember using the Company object for that earlier?) in a so called relative context. From this relative context, you can query the entire object tree by executing relative queries. This advanced use of Pointers offers great flexibility as the examples below illustrate.

To begin, here's how you create a relative context:

for(Iterator iter = context.iteratePointers("/departmentList[name='Sales'] /employees[age>30]"); iter.hasNext();){ Pointer empPtr = (Pointer)iter.next(); JXPathContext relativeContext = context.getRelativeContext(empPtr); }

In this code snippet, a new relative context is created for consecutive employee pointers.

Using the relative context, XPath queries can be executed on the entire object tree of siblings, children, and parent/grandparent objects, as the following snippet demonstrates:

//Current employee Employee emp = (Employee)relativeContext.getValue("."); //Employee name String name = (String)relativeContext.getValue("./name"); //Name of the Department this Employee belongs to (a parent object) String deptName = (String)relativeContext.getValue("../name"); //Name of the Company this Employee belongs to (a 'grandparent' object) String compName = (String)relativeContext.getValue("../../name"); //All coworkers of this Employee (sibling objects) for(Iterator empIter = relativeContext.iterate("../employees"); empIter.hasNext();){ Employee colleague = (Employee)empIter.next(); //... }

Summary

JXPath je izuzetno koristan alat za kretanje, kretanje i ispitivanje složenih stabala objekata. Budući da za upite koristi jezik izraza XPath, dostupan je velik broj referentnog materijala koji će vam pomoći u izgradnji učinkovitih, ali složenih upita za pronalaženje objekata. Još više fleksibilnosti dodaje se upotrebom Pointers i relativnog konteksta.

Ovaj kratki članak samo ogrebe površinu mogućnosti JXPath-a, za detaljniju raspravu s naprednijim primjerima korištenja pročitajte moj cjeloviti vodič.

Bart van Riel uključen je u Java i objektno orijentirani svijet više od sedam godina. Radio je i kao programer i trener u objektno orijentiranom i Java području. Trenutno je zaposlen u globalnoj IT konzultantskoj tvrtki Capgemini kao softverski arhitekt i protagonist otvorenog koda.

Saznajte više o ovoj temi

  • Preuzmite izvorni kod za ovaj članak
  • Pogledajte cjelovit vodič za JXPath
  • Apache Commons JXPath
  • Dobar vodič za XPath
  • Članke u JavaWorld je Alati za razvoj istraživačkog centra
  • Pratite novosti na JavaWorldu ! Prijavite se za naš besplatni bilten Enterprise Java

Ovu priču, "Upiti Java objekata pomoću JXPath" izvorno je objavio JavaWorld.