8000 [DomCrawler] Add support for XPath expression evaluation · symfony/symfony@3148fad · GitHub
[go: up one dir, main page]

Skip to content

Commit 3148fad

Browse files
committed
[DomCrawler] Add support for XPath expression evaluation
1 parent 695549f commit 3148fad

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)
0