New in Symfony 3.2: Added support for XPath expressions

Contributed by
Jakub Zalas
in #19430.

XPath is an expression language mostly used in web applications to select nodes in XML/HTML documents. Although selecting nodes with XPath is more complex than using CSS selectors, XPath is incredibly powerful and feature-rich.

Symfony provides XPath support via the DomCrawler component, which is commonly used in tests to validate that the contents of the given response are the expected ones. In Symfony 3.2 we improved XPath integration by adding support to evaluate XPath expressions.

In practice this means that you can perform advanced preprocessing of the information obtained via XPath to simplify the code of your tests. Consider for example the following HTML code:

1
2
3
4
5
6
7
$html = '<html>
<body>
    <span id="article-100" class="article">Article 1</span>
    <span id="article-101" class="article">Article 2</span>
    <span id="article-102" class="article">Article 3</span>
</body>
</html>';

Using the substring-after() XPath function you can get the numeric part of the id attribute of each node:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
use Symfony\Component\DomCrawler\Crawler;

$crawler = new Crawler();
$crawler->addHtmlContent($html);

$ids = $crawler->filterXPath('//span[contains(@id, "article-")]')
               ->evaluate('substring-after(@id, "-")');
// $ids = array:3 [
//   0 => "100"
//   1 => "101"
//   2 => "102"
// ]

Using the count() XPath function, you can for example get the number of <span> elements that contain the .article CSS class:

1
2
3
4
5
6
7
8
9
use Symfony\Component\DomCrawler\Crawler;

$crawler = new Crawler();
$crawler->addHtmlContent($html);

$num = $crawler->evaluate('count(//span[@class="article"])');
// $num = array:1 [
//   0 => 3.0
// ]

Read the MDN Xpath function reference for a quick overview of all the functions available and refer to the XPath and XQuery Functions document for the official W3C recommendation.

Comments

Comments are closed.

To ensure that comments stay relevant, they are closed for old posts.