Inleiding tot XPath met Java

1. Overzicht

In dit artikel gaan we het bespreken de basis van XPath met de ondersteuning in de standaard Java JDK.

We gaan een eenvoudig XML-document gebruiken, het verwerken en kijken hoe we het document kunnen doorlopen om de informatie die we nodig hebben eruit te halen.

XPath is een standaardsyntaxis die wordt aanbevolen door de W3C, het is een reeks uitdrukkingen om door XML-documenten te navigeren. U kunt hier een volledige XPath-referentie vinden.

2. Een eenvoudige XPath-parser

importeer javax.xml.namespace.NamespaceContext; importeer javax.xml.parsers.DocumentBuilder; importeer javax.xml.parsers.DocumentBuilderFactory; importeer javax.xml.parsers.ParserConfigurationException; importeer javax.xml.xpath.XPath; importeer javax.xml.xpath.XPathConstants; importeer javax.xml.xpath.XPathExpressionException; importeer javax.xml.xpath.XPathFactory; importeer org.w3c.dom.Document; openbare klasse DefaultParser {privé-bestandsbestand; openbare DefaultParser (bestandsbestand) {this.file = bestand; }} 

Laten we nu eens nader kijken naar de elementen die u in het DefaultParser:

FileInputStream fileIS = nieuwe FileInputStream (this.getFile ()); DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance (); DocumentBuilder-builder = builderFactory.newDocumentBuilder (); Document xmlDocument = builder.parse (fileIS); XPath xPath = XPathFactory.newInstance (). NewXPath (); String expression = "/ Tutorials / Tutorial"; nodeList = (NodeList) xPath.compile (expressie) .evaluate (xmlDocument, XPathConstants.NODESET);

Laten we dat opsplitsen:

DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance ();

We zullen dit object gebruiken om een ​​DOM-objectboom te maken vanuit ons xml-document:

DocumentBuilder-builder = builderFactory.newDocumentBuilder ();

Met een instantie van deze klasse kunnen we XML-documenten uit veel verschillende invoerbronnen ontleden, zoals InputStream, het dossier, URL en SAX:

Document xmlDocument = builder.parse (fileIS);

EEN Document (org.w3c.dom.Document) vertegenwoordigt het volledige XML-document, is de root van de documentboom, biedt onze eerste toegang tot gegevens:

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

Vanuit het XPath-object hebben we toegang tot de expressies en voeren ze uit over ons document om eruit te halen wat we nodig hebben:

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

We kunnen een XPath-expressie compileren die is doorgegeven als string en definiëren wat voor soort gegevens we verwachten dat een dergelijke NODESET, KNOOPPUNT of Draad bijvoorbeeld.

3. Laten we beginnen

Nu we een kijkje hebben genomen naar de basiscomponenten die we zullen gebruiken, laten we beginnen met wat code met behulp van enkele eenvoudige XML, voor testdoeleinden:

   Guava Introductie tot Guava 04/04/2016 GuavaAuthor XML Introductie tot XPath 04/05/2016 XMLAuthor 

3.1. Haal een basislijst met elementen op

De eerste methode is een eenvoudig gebruik van een XPath-expressie om een ​​lijst met knooppunten uit de XML op te halen:

FileInputStream fileIS = nieuwe FileInputStream (this.getFile ()); DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance (); DocumentBuilder-builder = builderFactory.newDocumentBuilder (); Document xmlDocument = builder.parse (fileIS); XPath xPath = XPathFactory.newInstance (). NewXPath (); String expression = "/ Tutorials / Tutorial"; nodeList = (NodeList) xPath.compile (expressie) .evaluate (xmlDocument, XPathConstants.NODESET); 

We kunnen de tutoriallijst in het hoofdknooppunt ophalen door de bovenstaande uitdrukking te gebruiken, of door de uitdrukking “// Zelfstudie”Maar deze zal alles ophalen knooppunten in het document vanaf het huidige knooppunt, ongeacht waar ze zich in het document bevinden, dit betekent op elk niveau van de boom, beginnend bij het huidige knooppunt.

De NodeList het keert terug door te specificeren NODESET aan de compileerinstructie als retourtype, is een geordende verzameling knooppunten die toegankelijk zijn door een index als parameter door te geven.

3.2. Een specifiek knooppunt ophalen op basis van zijn ID

We kunnen zoeken naar een element op basis van een gegeven ID door simpelweg te filteren:

DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance (); DocumentBuilder-builder = builderFactory.newDocumentBuilder (); Document xmlDocument = builder.parse (this.getFile ()); XPath xPath = XPathFactory.newInstance (). NewXPath (); String expression = "/ Tutorials / Tutorial [@ tutId =" + "'" + id + "'" + "]"; node = (Node) xPath.compile (expressie) .evaluate (xmlDocument, XPathConstants.NODE); 

Door dit soort uitdrukkingen te gebruiken, kunnen we filteren op elk element waarnaar we moeten zoeken, gewoon door de juiste syntaxis te gebruiken. Dit soort uitdrukkingen worden predikaten genoemd en zijn een gemakkelijke manier om specifieke gegevens over een document te lokaliseren, bijvoorbeeld:

/ Tutorials / Tutorial [1]

/ Tutorials / Tutorial [eerste ()]

/ Tutorials / Tutorial [position () <4]

Een volledige referentie van predikaten vindt u hier

3.3. Nodes ophalen met een specifieke tagnaam

Nu gaan we verder door assen te introduceren, laten we eens kijken hoe dit werkt door het in een XPath-expressie te gebruiken:

Document xmlDocument = builder.parse (this.getFile ()); this.clean (xmlDocument); XPath xPath = XPathFactory.newInstance (). NewXPath (); String expression = "// Tutorial [afstammeling :: titel [text () =" + "'" + naam + "'" + "]]"; nodeList = (NodeList) xPath.compile (expressie) .evaluate (xmlDocument, XPathConstants.NODESET); 

Met de bovenstaande uitdrukking zijn we op zoek naar alles element dat een afstammeling heeft met de tekst doorgegeven als parameter in de "naam" variabele.

Als we de voorbeeld-xml voor dit artikel volgen, kunnen we zoeken naar een met de tekst "Guava" of "XML" en we zullen het geheel ophalen element met al zijn gegevens.

Axes bieden een zeer flexibele manier om door een XML-document te navigeren en u kunt een volledige documentatie vinden op de officiële site.

3.4. Gegevens manipuleren in uitdrukkingen

XPath stelt ons in staat om indien nodig ook gegevens in de uitdrukkingen te manipuleren.

XPath xPath = XPathFactory.newInstance (). NewXPath (); String expression = "// Tutorial [number (translate (date, '/', ''))>" + date + "]"; nodeList = (NodeList) xPath.compile (expressie) .evaluate (xmlDocument, XPathConstants.NODESET); 

In deze uitdrukking geven we aan onze methode een eenvoudige tekenreeks door als een datum die eruitziet als "ddmmjjjj", maar de XML slaat deze gegevens op met de indeling "dd / mm / jjjj", Dus om een ​​resultaat te matchen, manipuleren we de tekenreeks om deze te converteren naar het juiste gegevensformaat dat door ons document wordt gebruikt en we doen het door een van de functies van XPath te gebruiken

3.5. Elementen ophalen uit een document met een gedefinieerde naamruimte

Als ons xml-document een naamruimte heeft gedefinieerd zoals het is in de voorbeeld_namespace.xml die hier wordt gebruikt, zullen de regels om de gegevens op te halen die we nodig hebben, veranderen aangezien onze xml als volgt begint:

Als we nu een uitdrukking gebruiken die lijkt op '// Tutorial ”, zullen we geen resultaat krijgen. Die XPath-expressie zal alles retourneren elementen die niet onder een naamruimte vallen, en in onze nieuwe example_namespace.xml, all elementen worden gedefinieerd in de naamruimte / volledig_archief.

Laten we eens kijken hoe om te gaan met naamruimten.

Allereerst moeten we de naamruimtecontext instellen, zodat XPath kan weten waar we naar onze gegevens zoeken:

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 (" bdn ".equals (arg0)) {return" / full_archive ";} return null;}}); 

In de bovenstaande methode definiëren we "bdn"Als de naam voor onze naamruimte"/ volledig_archief", En vanaf nu moeten we"bdn”Naar de XPath-expressies die worden gebruikt om elementen te lokaliseren:

String expression = "/ bdn: Tutorials / bdn: Tutorial"; nodeList = (NodeList) xPath.compile (expressie) .evaluate (xmlDocument, XPathConstants.NODESET); 

Met behulp van de bovenstaande uitdrukking zijn we in staat om alles terug te vinden elementen onder 'bdn”Naamruimte.

3.6. Problemen met lege tekstknooppunten vermijden

Zoals je kon zien, wordt in de code in de 3.3-sectie van dit artikel een nieuwe functie aangeroepen, precies nadat we onze XML naar een Document-object hebben geparseerd, deze .clean (xmlDocument);

Soms, wanneer we door elementen, childnodes, enzovoort, herhalen, als ons document lege tekstknooppunten heeft, kunnen we onverwacht gedrag vinden in de resultaten die we willen krijgen.

We belden knooppunt .getFirstChild () wanneer we alles herhalen elementen op zoek naar de informatie, maar in plaats van wat we zoeken, hebben we gewoon "#Text" als een leeg knooppunt.

Om het probleem op te lossen, kunnen we door ons document navigeren en die lege knooppunten als volgt verwijderen:

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

Door dit te doen, kunnen we elk type knooppunt dat we vinden controleren en de knooppunten verwijderen die we niet nodig hebben.

4. Conclusies

Hier hebben we zojuist de standaard XPath-ondersteuning geïntroduceerd, maar er zijn nu veel populaire bibliotheken zoals JDOM, Saxon, XQuery, JAXP, Jaxen of zelfs Jackson. Er zijn ook bibliotheken voor specifieke HTML-parsing, zoals JSoup.

Het is niet beperkt tot java, XPath-expressies kunnen door XSLT-taal worden gebruikt om door XML-documenten te navigeren.

Zoals u kunt zien, is er een breed scala aan mogelijkheden om met dit soort bestanden om te gaan.

Er is standaard een geweldige standaardondersteuning voor het parseren, lezen en verwerken van XML / HTML-documenten. U kunt het volledige werkende voorbeeld hier vinden.