Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a0b22f0

Browse files
committed
feature #19430 [DomCrawler] Add support for XPath expression evaluation (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
2 parents 983b560 + 3148fad commit a0b22f0

File tree

2 files changed

+75
-0
lines changed

2 files changed

+75
-0
lines changed

src/Symfony/Component/DomCrawler/Crawler.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,36 @@ public function html()
592592
return $html;
593593
}
594594

595+
/**
596+
* Evaluates an XPath expression.
597+
*
598+
* Since an XPath expression might evaluate to either a simple type or a \DOMDoneList,
599+
* this method will return either an array of simple types or a new Crawler instance.
600+
*
601+
* @param string $xpath An XPath expression
602+
*
603+
* @return array|Crawler An array of evaluation results or a new Crawler instance
604+
*/
605+
public function evaluate($xpath)
606+
{
607+
if (null === $this->document) {
608+
throw new \LogicException('Cannot evaluate the expression on an uninitialized crawler.');
609+
}
610+
611+
$data = array();
612+
$domxpath = $this->createDOMXPath($this->document, $this->findNamespacePrefixes($xpath));
613+
614+
foreach ($this->nodes as $node) {
615+
$data[] = $domxpath->evaluate($xpath, $node);
616+
}
617+
618+
if (isset($data[0]) && $data[0] instanceof \DOMNodeList) {
619+
return $this->createSubCrawler($data);
620+
}
621+
622+
return $data;
623+
}
624+
595625
/**
596626
* Extracts information from the list of nodes.
597627
*

src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,6 +1061,51 @@ public function testCountOfNestedElements()
10611061
$this->assertCount(1, $crawler->filter('li:contains("List item 1")'));
10621062
}
10631063

1064+
public function testEvaluateReturnsTypedResultOfXPathExpressionOnADocumentSubset()
1065+
{
1066+
$crawler = $this->createTestCrawler();
1067+
1068+
$result = $crawler->filterXPath('//form/input')->evaluate('substring-before(@name, "Name")');
1069+
1070+
$this->assertSame(array('Text', 'Foo', 'Bar'), $result);
1071+
}
1072+
1073+
public function testEvaluateReturnsTypedResultOfNamespacedXPathExpressionOnADocumentSubset()
1074+
{
1075+
$crawler = $this->createTestXmlCrawler();
1076+
1077+
$result = $crawler->filterXPath('//yt:accessControl/@action')->evaluate('string(.)');
1078+
1079+
$this->assertSame(array('comment', 'videoRespond'), $result);
1080+
}
1081+
1082+
public function testEvaluateReturnsTypedResultOfNamespacedXPathExpression()
1083+
{
1084+
$crawler = $this->createTestXmlCrawler();
1085+
$crawler->registerNamespace('youtube', 'http://gdata.youtube.com/schemas/2007');
1086+
1087+
$result = $crawler->evaluate('string(//youtube:accessControl/@action)');
1088+
1089+
$this->assertSame(array('comment'), $result);
1090+
}
1091+
1092+
public function testEvaluateReturnsACrawlerIfXPathExpressionEvaluatesToANode()
1093+
{
1094+
$crawler = $this->createTestCrawler()->evaluate('//form/input[1]');
1095+
1096+
$this->assertInstanceOf(Crawler::class, $crawler);
1097+
$this->assertCount(1, $crawler);
1098+
$this->assertSame('input', $crawler->first()->nodeName());
1099+
}
1100+
1101+
/**
1102+
* @expectedException \LogicException
1103+
*/
1104+
public function testEvaluateThrowsAnExceptionIfDocumentIsEmpty()
1105+
{
1106+
(new Crawler())->evaluate('//form/input[1]');
1107+
}
1108+
10641109
public function createTestCrawler($uri = null)
10651110
{
10661111
$dom = new \DOMDocument();

0 commit comments

Comments
 (0)