Use XPath in HTML with Java

To use XPath in HTML with Java, load an HTMLDocument, pass an XPath expression to document.evaluate(), request a node result with XPathResultType.Any, and call iterateNext() on the returned IXPathResult.

XPath uses path expressions to select nodes by element name, attributes, position, text, and relationships within a document tree. It is useful for HTML queries that depend on ancestors, descendants, or conditions that are difficult to express with CSS selectors.

This article explains the evaluate() parameters and demonstrates how to select HTML nodes from an inline string and extract photo source URLs from an existing HTML file.

XPath Expressions for HTML

The following XPath expressions cover common HTML selection tasks:

TaskXPath expression
Select all images//img
Select an element by ID//*[@id = 'content']
Select images with an alt attribute//img[@alt]
Select images inside <main>//main//img
Select the first image in the document(//img)[1]
Select images whose class value is exactly photo//img[@class = 'photo']
Match photo in a multi-value class attribute//img[contains(concat(' ', normalize-space(@class), ' '), ' photo ')]
Select paragraphs containing specific text//p[contains(normalize-space(.), 'Release notes')]

An expression beginning with // searches from the document context. An expression beginning with .// searches descendants of the context node supplied to evaluate().

Evaluate an XPath Expression in Java

The evaluate() method accepts five arguments:

The following example selects paragraphs whose data-status attribute equals published and prints their text:

  1. Create an HTMLDocument from the HTML string.
  2. Evaluate //p[@data-status = 'published'] against the document.
  3. Request XPathResultType.Any and pass null for the resolver and reusable result.
  4. Call iterateNext() until every matching node has been processed.
 1import com.aspose.html.HTMLDocument;
 2import com.aspose.html.dom.Node;
 3import com.aspose.html.dom.xpath.IXPathResult;
 4import com.aspose.html.dom.xpath.XPathResultType;
 5
 6String html = "<section>"
 7        + "<p data-status='published'>Getting Started</p>"
 8        + "<p data-status='draft'>Migration Notes</p>"
 9        + "<p data-status='published'>API Reference</p>"
10        + "</section>";
11
12HTMLDocument document = new HTMLDocument(html, ".");
13IXPathResult result = document.evaluate(
14        "//p[@data-status = 'published']",
15        document,
16        null,
17        XPathResultType.Any,
18        null
19);
20
21for (Node node; (node = result.iterateNext()) != null; ) {
22    System.out.println(node.getTextContent());
23}

The XPath predicate excludes the draft paragraph, so the console output is:

Getting Started
API Reference

Build an XPath Query to Select Images

The sample file xpath-image.htm contains advertising images in its header and footer. Its <main> element contains alternating photo rows and advertising rows, while some photo rows also contain inline banners.

The XPath expression can be refined in stages to exclude each unwanted group.

Select All Image Elements

The expression //img selects every image in the document, including photos and advertising images in the header, main content, and footer:

1IXPathResult result = document.evaluate(
2        "//img", document, null, XPathResultType.Any, null
3);

Limit the query to the <main> element with //main//img. This excludes header and footer images but still selects advertising images inside the main content:

1IXPathResult result = document.evaluate(
2        "//main//img", document, null, XPathResultType.Any, null
3);

Exclude Advertising Rows

In the sample HTML, odd-positioned div children of <main> contain the photo rows. The expression //main/div[position() mod 2 = 1]//img excludes the separate advertising rows but still includes inline banners within the photo rows:

1IXPathResult result = document.evaluate(
2        "//main/div[position() mod 2 = 1]//img",
3        document,
4        null,
5        XPathResultType.Any,
6        null
7);

Select Only Photo Images

Add an attribute predicate to select only images whose class value is exactly photo:

1//main/div[position() mod 2 = 1]//img[@class = 'photo']

Use the token-aware expression below instead when photo can be one of several classes on the same element:

1//main/div[position() mod 2 = 1]//img[contains(concat(' ', normalize-space(@class), ' '), ' photo ')]

Extract Image Source URLs with XPath in Java

The following Java example loads xpath-image.htm, selects the photo elements with the final XPath expression, casts each returned node to HTMLImageElement, and prints its source URL:

  1. Download xpath-image.htm to the application’s working directory.
  2. Load the HTML file into an HTMLDocument.
  3. Pass the photo-selection expression to document.evaluate().
  4. Iterate through the returned nodes and cast each one to HTMLImageElement.
  5. Call getSrc() to read and print each selected image source URL.
 1import com.aspose.html.HTMLDocument;
 2import com.aspose.html.HTMLImageElement;
 3import com.aspose.html.dom.Node;
 4import com.aspose.html.dom.xpath.IXPathResult;
 5import com.aspose.html.dom.xpath.XPathResultType;
 6
 7String inputPath = "xpath-image.htm";
 8HTMLDocument document = new HTMLDocument(inputPath);
 9
10String xpath = "//main/div[position() mod 2 = 1]//img[@class = 'photo']";
11IXPathResult result = document.evaluate(
12        xpath,
13        document,
14        document.createNSResolver(document),
15        XPathResultType.Any,
16        null
17);
18
19for (Node node; (node = result.iterateNext()) != null; ) {
20    HTMLImageElement image = (HTMLImageElement) node;
21    System.out.println(image.getSrc());
22}

For the supplied file, the expression matches 12 photo elements. Repeated images produce repeated source URLs. The code reports the selected image locations; it does not download the image files.

Common XPath Issues

IssueCause and fix
The result contains no nodesThe expression does not match the loaded DOM. Test a broader expression such as //img before adding predicates.
Elements with class="photo featured" are skipped@class = 'photo' matches only an attribute whose complete value is photo. Use the token-aware contains() expression shown above when an element can have several classes.
A query searches the wrong part of the documentCheck the context node. Use // for a document-wide expression and .// for descendants relative to a selected context node.
A cast failsThe XPath result contains a different node type. Make the expression select the expected element type before casting.
An XPath text condition misses visible textIndentation, repeated spaces, or text inside child elements can change the value being compared. Use normalize-space(.) to compare the normalized text of the element and its descendants.

FAQ

When should I use XPath instead of CSS selectors?

Use XPath when selection depends on ancestors, node positions, text conditions, or other structural relationships that would be awkward to express with CSS. Use CSS selectors for familiar matching by tag, class, ID, or attribute.

How do I select an HTML element by attribute with XPath?

Place the attribute condition in a predicate. For example, //img[@alt] selects images that have an alt attribute, while //input[@name = 'email'] selects inputs whose name value is email.

Can XPath select an element by its text?

Yes. For example, //p[contains(normalize-space(.), 'Release notes')] selects paragraphs whose normalized descendant text contains the specified phrase.

What happens when an XPath expression matches nothing?

For an iterable node result, iterateNext() returns null when there are no matching nodes or when iteration has reached the end of the result.

Does document.evaluate() modify or remove matching nodes?

No. document.evaluate() evaluates the expression and returns a result. To edit or remove selected nodes, retrieve them from the result and perform the required DOM operations explicitly.

Related Articles