Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DomCrawler] Add support for XPath expression evaluation #19430

Merged
merged 1 commit into from Aug 2, 2016

Conversation

jakzal
Copy link
Contributor

@jakzal jakzal commented Jul 26, 2016

Q A
Branch? master
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets #19162
License MIT
Doc PR TODO

Example usage:

<?php

use Symfony\Component\DomCrawler\Crawler;
use Symfony\Component\VarDumper\VarDumper;

require_once __DIR__.'/vendor/autoload.php';

$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>';

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

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

VarDumper::dump($crawler->evaluate('substring-after(//span[contains(@id, "article-")]/@id, "-")'));
// array:1 [
//   0 => "100"
// ]

VarDumper::dump($crawler->filterXPath('//span[@class="article"]')->evaluate('count(@id)'));
// array:3 [
//   0 => 1.0
//   1 => 1.0
//   2 => 1.0
// ]

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

VarDumper::dump($crawler->evaluate('//span[1]'));
// Symfony\Component\DomCrawler\Crawler { }

$prefixes = $this->findNamespacePrefixes($xpath);

foreach ($this->nodes as $node) {
$domxpath = $this->createDOMXPath($node->ownerDocument, $prefixes);
Copy link
Member

@stof stof Jul 26, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can use a single DOMXPath now. As of Symfony 3, it is impossible to have nodes belonging to different documents. They will all belong to $this->document (which can only be null for an empty root crawler, i.e. a crawler not yet initialized)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! PR updated.

{
$data = array();
$prefixes = $this->findNamespacePrefixes($xpath);
$domxpath = $this->createDOMXPath($this->document, $prefixes);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would throw a LogicException before that in case $this->document is null, saying you cannot evaluate an expression on an uninitialized crawler.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 done

*
* @param string $xpath An XPath expression
*
* @return array|Crawler An array of evaluation results or a new Crawler instance
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

returning an array of a Crawler makes it difficult to work with this method in a fluent interface. This would be the first method returning a Crawler or something else.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I thought twice before defining the return type. I also don't like it but the DOMXPath::evaluate() returns a simple type value or DOMNodeList. The result depends on the type of xpath query. I figured that the end user knows what it's gonna be since he wrote the query.

Not sure how we could solve it differently (other than defining two methods and verifying results, or forbidding one type of queries).

@mpyw
Copy link

mpyw commented Aug 2, 2016

+1 👍

@fabpot
Copy link
Member

fabpot commented Aug 2, 2016

Thank you @jakzal.

@fabpot fabpot merged commit 3148fad into symfony:master Aug 2, 2016
fabpot added a commit that referenced this pull request Aug 2, 2016
…on (jakzal)

This PR was merged into the 3.2-dev branch.

Discussion
----------

[DomCrawler] Add support for XPath expression evaluation

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #19162
| License       | MIT
| Doc PR        | TODO

Example usage:

```php
<?php

use Symfony\Component\DomCrawler\Crawler;
use Symfony\Component\VarDumper\VarDumper;

require_once __DIR__.'/vendor/autoload.php';

$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>';

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

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

VarDumper::dump($crawler->evaluate('substring-after(//span[contains(@id, "article-")]/@id, "-")'));
// array:1 [
//   0 => "100"
// ]

VarDumper::dump($crawler->filterXPath('//span[@Class="article"]')->evaluate('count(@id)'));
// array:3 [
//   0 => 1.0
//   1 => 1.0
//   2 => 1.0
// ]

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

VarDumper::dump($crawler->evaluate('//span[1]'));
// Symfony\Component\DomCrawler\Crawler { }
```

Commits
-------

3148fad [DomCrawler] Add support for XPath expression evaluation
@jakzal jakzal deleted the domcrawler-evaluate branch August 4, 2016 06:35
@fabpot fabpot mentioned this pull request Oct 27, 2016
wouterj added a commit to symfony/symfony-docs that referenced this pull request Nov 10, 2016
This PR was merged into the master branch.

Discussion
----------

[DomCrawler] Document XPath expression evaluation

Documents symfony/symfony#19430

Commits
-------

156b047 [DomCrawler] Document XPath expression evaluation
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants