Uvod u XPath s Javom

1. Pregled

U ovom ćemo članku ići dalje osnove XPath-a s podrškom u standardnom Java JDK-u.

Koristit ćemo jednostavan XML dokument, obraditi ga i vidjeti kako preći preko dokumenta kako bismo iz njega izvukli potrebne podatke.

XPath je standardna sintaksa koju preporučuje W3C, skup je izraza za kretanje kroz XML dokumente. Cijelu referencu XPath možete pronaći ovdje.

2. Jednostavan raščlanjivač XPath

uvoz javax.xml.namespace.NamespaceContext; uvoz javax.xml.parsers.DocumentBuilder; uvoz javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; uvoz javax.xml.xpath.XPath; uvoz javax.xml.xpath.XPathConstants; uvoz javax.xml.xpath.XPathExpressionException; uvoz javax.xml.xpath.XPathFactory; import org.w3c.dom.Document; javna klasa DefaultParser {privatna datoteka; javni DefaultParser (datoteka datoteke) {this.file = datoteka; }} 

Sada ćemo bliže pogledati elemente koje ćete pronaći u DefaultParser:

FileInputStream fileIS = novi FileInputStream (this.getFile ()); DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance (); Builder DocumentBuilder = builderFactory.newDocumentBuilder (); Dokument xmlDocument = builder.parse (fileIS); XPath xPath = XPathFactory.newInstance (). NewXPath (); String izraz = "/ Tutoriali / Tutorial"; nodeList = (NodeList) xPath.compile (izraz) .evaluate (xmlDocument, XPathConstants.NODESET);

Razdvojimo to:

DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance ();

Ovaj ćemo objekt koristiti za izradu stabla DOM objekata iz našeg xml dokumenta:

Builder DocumentBuilder = builderFactory.newDocumentBuilder ();

Imajući primjerak ove klase, možemo raščlaniti XML dokumente iz mnogih različitih ulaznih izvora poput InputStream, Datoteka, URL i SAKSOFON:

Dokument xmlDocument = builder.parse (fileIS);

A Dokument (org.w3c.dom.Dokument) predstavlja cjelokupni XML dokument, korijen je stabla dokumenata, pruža nam prvi pristup podacima:

XPath xPath = XPathFactory.newInstance (). NewXPath ();

Iz XPath objekta pristupit ćemo izrazima i izvršiti ih preko našeg dokumenta kako bismo iz njega izdvojili što nam treba:

xPath.compile (izraz) .evaluate (xmlDocument, XPathConstants.NODESET);

Možemo sastaviti izraz XPath koji se prosljeđuje kao niz i definirati kakve podatke očekujemo da će primiti takav NODESET, ČVOR ili Niz na primjer.

3. Krenimo

Sad kad smo pogledali osnovne komponente koje ćemo koristiti, počnimo s nekim kodom koji koristi neki jednostavni XML, u svrhu testiranja:

   Guava Uvod u Guavu 04/04/2016 GuavaAuthor XML Uvod u XPath 04/05/2016 XMLAuthor 

3.1. Dohvatite osnovni popis elemenata

Prva metoda je jednostavna upotreba XPath izraza za dohvaćanje popisa čvorova iz XML-a:

FileInputStream fileIS = novi FileInputStream (this.getFile ()); DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance (); Builder DocumentBuilder = builderFactory.newDocumentBuilder (); Dokument xmlDocument = builder.parse (fileIS); XPath xPath = XPathFactory.newInstance (). NewXPath (); Izraz niza = "/ Tutoriali / Tutorial"; nodeList = (NodeList) xPath.compile (izraz) .evaluate (xmlDocument, XPathConstants.NODESET); 

Popis tutorijala koji se nalazi u korijenskom čvoru možemo dohvatiti pomoću gornjeg izraza ili pomoću izraza „// Vodič”Ali ovaj će dohvatiti sve čvorovi u dokumentu iz trenutnog čvora, bez obzira gdje se nalaze u dokumentu, to znači na bilo kojoj razini stabla počevši od trenutnog čvora.

The NodeList vraća se specificiranjem NODESET uputi za sastavljanje kao povratnom obliku je uređena kolekcija čvorova kojima se može pristupiti prosljeđivanjem indeksa kao parametra.

3.2. Dohvaćanje određenog čvora prema njegovom ID-u

Element možemo tražiti na temelju bilo kojeg određenog id-a samo filtriranjem:

DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance (); Builder DocumentBuilder = builderFactory.newDocumentBuilder (); Dokument xmlDocument = builder.parse (this.getFile ()); XPath xPath = XPathFactory.newInstance (). NewXPath (); String expression = "/ Tutorials / Tutorial [@ tutId =" + "'" + id + "'" + "]"; čvor = (čvor) xPath.compile (izraz) .evaluate (xmlDocument, XPathConstants.NODE); 

Korištenjem ove vrste izraza možemo filtrirati bilo koji element koji trebamo potražiti samo pomoću ispravne sintakse. Takve se izraze nazivaju predikati i oni su jednostavan način lociranja određenih podataka u dokumentu, na primjer:

/ Vodiči / Vodič [1]

/ Vodiči / Vodič [prvi ()]

/ Vodiči / Vodič [položaj () <4]

Kompletnu referencu predikata možete pronaći ovdje

3.3. Dohvaćanje čvorova određenim nazivom oznake

Sada idemo dalje uvođenjem osi, da vidimo kako ovo funkcionira koristeći ga u izrazu XPath:

Dokument xmlDocument = builder.parse (this.getFile ()); this.clean (xmlDocument); XPath xPath = XPathFactory.newInstance (). NewXPath (); Izraz niza = "// Vodič [potomak :: naslov [tekst () =" + "'" + ime + "'" + "]]"; nodeList = (NodeList) xPath.compile (izraz) .evaluate (xmlDocument, XPathConstants.NODESET); 

Uz gore korišteni izraz, tražimo svaki element koji ima potomka s tekstom koji je proslijeđen kao parametar u varijabli “name”.

Slijedeći uzorak xml-a za ovaj članak, mogli bismo potražiti koji sadrži tekst "Guava" ili "XML" i dohvatit ćemo cjelinu element sa svim svojim podacima.

Osovine pružaju vrlo fleksibilan način kretanja XML dokumentom i na službenoj stranici možete pronaći cjelovitu dokumentaciju.

3.4. Manipuliranje podacima u izrazima

XPath nam omogućuje manipuliranje podacima i u izrazima ako je potrebno.

XPath xPath = XPathFactory.newInstance (). NewXPath (); Izraz niza = "// Vodič [broj (prijevod (datum, '/', ''))>" + datum + "]"; nodeList = (NodeList) xPath.compile (izraz) .evaluate (xmlDocument, XPathConstants.NODESET); 

U ovom izrazu našoj metodi prenosimo jednostavan niz kao datum koji izgleda kao „ddmmyyyy“, ali XML pohranjuje te podatke u formatu „dd / mm / gggg“, Tako da bismo podudarali rezultat, manipuliramo nizom kako bismo ga pretvorili u ispravan format podataka koji koristi naš dokument i to radimo pomoću jedne od funkcija koje pruža XPath

3.5. Dohvaćanje elemenata iz dokumenta s definiranim prostorom imena

Ako naš xml dokument ima prostor imena definiran onako kako je ovdje korišten example_namespace.xml, pravila za dohvat podataka koji su nam potrebni promijenit će se budući da naš xml započinje ovako:

Sada kada koristimo izraz sličan "// Tutorijal ”, nećemo postići nikakav rezultat. Taj XPath izraz vratit će sve elementi koji nisu ni pod kojim prostorom imena, a u našem novom example_namespace.xml, svi elementi su definirani u prostoru imena / full_archive.

Pogledajmo kako se rukuje prostorima imena.

Prije svega moramo postaviti kontekst prostora imena kako bi XPath mogao znati gdje tražimo svoje podatke:

xPath.setNamespaceContext (new NamespaceContext () {@Override public Iterator getPrefixes (String arg0) {return null;} @Override public String getPrefix (String arg0) {return null;} @Override public String getNamespaceURI (String arg0) {if (String arg0) { bdn ".equals (arg0)) {return" / full_archive ";} return null;}}); 

U gornjoj metodi definiramo “bdn"Kao naziv za naš prostor imena"/ full_archive", A od sada moramo dodati"bdn”Na izraze XPath koji se koriste za lociranje elemenata:

Izraz niza = "/ bdn: Tutoriali / bdn: Tutorial"; nodeList = (NodeList) xPath.compile (izraz) .evaluate (xmlDocument, XPathConstants.NODESET); 

Korištenjem gornjeg izraza možemo dohvatiti sve elementi pod “bdn”Prostor imena.

3.6. Izbjegavanje problema s praznim tekstualnim čvorovima

Kao što ste mogli primijetiti, u kodu iz odjeljka 3.3 ovog članka nova se funkcija poziva odmah nakon raščlanjivanja našeg XML-a na objekt Document, ovaj .clean (xmlDocument);

Ponekad, kad prelazimo kroz elemente, podređene čvorove i tako dalje, ako naš dokument ima prazne čvorove teksta, možemo pronaći neočekivano ponašanje u rezultatima koje želimo dobiti.

Nazvali smo čvor .getFirstChild () kad se ponavljamo nad svima elementi koji traže informacije, ali umjesto onoga što tražimo, samo je #Text prazan čvor.

Da bismo riješili problem, možemo se kretati kroz naš dokument i uklanjati one prazne čvorove, poput ovog:

NodeList childs = node.getChildNodes (); for (int n = childs.getLength () - 1; n> = 0; n--) {Čvor child = childs.item (n); kratki nodeType = child.getNodeType (); if (nodeType == Node.ELEMENT_NODE) ​​{clean (child); } else if (nodeType == Node.TEXT_NODE) ​​{String trimmedNodeVal = child.getNodeValue (). trim (); if (trimmedNodeVal.length () == 0) {node.removeChild (dijete); } else {dijete.setNodeValue (trimmedNodeVal); }} else if (nodeType == Node.COMMENT_NODE) ​​{node.removeChild (dijete); }}

Na taj način možemo provjeriti svaku vrstu čvora koji pronađemo i ukloniti one koji nam nisu potrebni.

4. Zaključci

Ovdje smo upravo uveli zadani XPath koji pruža podršku, ali postoje mnoge popularne knjižnice kao što su JDOM, Saxon, XQuery, JAXP, Jaxen ili čak Jackson. Postoje biblioteke za specifično HTML raščlanjivanje, poput JSoupa.

Nije ograničen na javu, XPath izrazi mogu se koristiti jezikom XSLT za navigaciju XML dokumentima.

Kao što vidite, postoji širok raspon mogućnosti rukovanja ovakvim datotekama.

Standardno postoji velika standardna podrška za raščlanjivanje, čitanje i obradu XML / HTML dokumenata. Cjeloviti radni uzorak možete pronaći ovdje.