import javax.xml.xpath.*; import javax.xml.parsers.*; import org.w3c.dom.*; import java.io.*; // 1. Parse the XML into a DOM Document DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); Document doc = dbf.newDocumentBuilder() .parse(new ByteArrayInputStream(xmlBytes)); // 2. Create an XPath instance XPathFactory xpf = XPathFactory.newInstance(); XPath xpath = xpf.newXPath(); // 3. Evaluate an expression — returns a String result String title = (String) xpath.evaluate( "/library/book[1]/title", doc, XPathConstants.STRING); System.out.println(title); // e.g. "Clean Code" XPath instances are not thread-safe. Create one per thread or use XPathExpression (compile once, evaluate concurrently is also not safe without synchronisation). Cache XPathFactory which is thread-safe.
XPathConstantsJava type returnedUse for
STRINGStringText content of first matching node
NUMBERDoubleNumeric expressions, count()
BOOLEANBooleanExistence checks, predicates
NODENodeFirst matching node
NODESETNodeListMultiple matching nodes
XPath xpath = XPathFactory.newInstance().newXPath(); // Get a single string String author = (String) xpath.evaluate("/library/book[2]/author", doc, XPathConstants.STRING); // Get a NodeList of all books NodeList books = (NodeList) xpath.evaluate("//book", doc, XPathConstants.NODESET); System.out.println("Books: " + books.getLength()); // Get a single Node Node firstBook = (Node) xpath.evaluate("//book[1]", doc, XPathConstants.NODE); // Count books double count = (Double) xpath.evaluate("count(//book)", doc, XPathConstants.NUMBER); System.out.println("Count: " + (int) count); // Boolean check — does any book with year > 2010 exist? boolean hasRecent = (Boolean) xpath.evaluate( "count(//book[year > 2010]) > 0", doc, XPathConstants.BOOLEAN);
ExpressionSelects
/libraryRoot element named library
//bookAll book elements anywhere in the document
/library/book[1]First book child of library (1-indexed)
/library/book[last()]Last book element
//book[@id='2']book with attribute id="2"
//book[@genre]All books that have a genre attribute
//book[year > 2010]Books where year element value > 2010
//book/title/text()Text nodes inside title elements
//@idAll id attributes anywhere
//book[contains(title,'Java')]Books whose title contains "Java"
count(//book)Number of book elements
string-length(//book[1]/title)Length of first book's title
normalize-space(//title)Trimmed, collapsed whitespace of title

If you evaluate the same XPath against many documents, compile it once with xpath.compile().

XPath xpath = XPathFactory.newInstance().newXPath(); // Compile once — reuse many times XPathExpression titleExpr = xpath.compile("//book/title"); XPathExpression authorExpr = xpath.compile("//book/author"); // Evaluate against different documents for (Document doc : documents) { NodeList titles = (NodeList) titleExpr.evaluate(doc, XPathConstants.NODESET); NodeList authors = (NodeList) authorExpr.evaluate(doc, XPathConstants.NODESET); // process... } XPathExpression is also not thread-safe. Do not share compiled expressions across threads without synchronisation. Use a ThreadLocal<XPathExpression> or create a new one per evaluation in concurrent code.

To query namespace-qualified elements, register a NamespaceContext on the XPath instance.

import javax.xml.namespace.NamespaceContext; import java.util.Iterator; // XML: <bk:library xmlns:bk="http://example.com/books"><bk:book>... XPath xpath = XPathFactory.newInstance().newXPath(); xpath.setNamespaceContext(new NamespaceContext() { @Override public String getNamespaceURI(String prefix) { return switch (prefix) { case "bk" -> "http://example.com/books"; default -> javax.xml.XMLConstants.NULL_NS_URI; }; } @Override public String getPrefix(String uri) { return null; } @Override public Iterator<String> getPrefixes(String uri) { return null; } }); // Now use the registered prefix in XPath expressions NodeList books = (NodeList) xpath.evaluate( "//bk:book", doc, XPathConstants.NODESET); System.out.println("Found: " + books.getLength());

XPath can evaluate directly against an InputSource without building a DOM first — useful for one-off queries on large files.

XPath xpath = XPathFactory.newInstance().newXPath(); // Evaluate against a file stream — no full DOM built String title = (String) xpath.evaluate( "/library/book[1]/title", new org.xml.sax.InputSource(new FileInputStream("library.xml")), XPathConstants.STRING); System.out.println(title); When evaluating against an InputSource, the XPath engine builds an internal minimal representation. For multiple expressions on the same document, parse to DOM first and reuse the Document — evaluating repeatedly from InputSource re-parses each time.