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

Skip to content

Commit 8dc322b

Browse files
committed
fix axes handling in Crawler::filterXPath()
Due to some limitations in the relativize() method, it was not possible to use XPath axes other than descendant or descendant-or-self in the filterXPath() method of the Crawler class. This commit adds support for the ancestor, ancestor-or-self, attribute, child, following, following-sibling, parent, preceding, preceding-sibling and self axes.
1 parent cd005e6 commit 8dc322b

File tree

2 files changed

+69
-1
lines changed

2 files changed

+69
-1
lines changed

src/Symfony/Component/DomCrawler/Crawler.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -854,7 +854,7 @@ private function relativize($xpath)
854854
$expression = $nonMatchingExpression;
855855
} elseif (0 === strpos($expression, 'descendant::')) {
856856
$expression = 'descendant-or-self::' . substr($expression, strlen('descendant::'));
857-
} elseif (0 !== strpos($expression, 'descendant-or-self::')) {
857+
} elseif (!preg_match('/^(ancestor|ancestor-or-self|attribute|child|descendant-or-self|following|following-sibling|parent|preceding|preceding-sibling|self)::/', $expression)) {
858858
$expression = 'self::' .$expression;
859859
}
860860
$expressions[] = $parenthesis.$expression;

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

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,74 @@ public function testFilterXPath()
411411
$this->assertCount(3, $crawler->filterXPath('//body')->filterXPath('//button')->parents(), '->filterXpath() preserves parents when chained');
412412
}
413413

414+
public function testFilterXPathWithAncestorAxis()
415+
{
416+
$crawler = $this->createTestCrawler()->filterXPath('//form');
417+
418+
$this->assertCount(2, $crawler->filterXPath('ancestor::*'));
419+
}
420+
421+
public function testFilterXPathWithAncestorOrSelfAxis()
422+
{
423+
$crawler = $this->createTestCrawler()->filterXPath('//form');
424+
425+
$this->assertCount(3, $crawler->filterXPath('ancestor-or-self::*'));
426+
}
427+
428+
public function testFilterXPathWithAttributeAxis()
429+
{
430+
$crawler = $this->createTestCrawler()->filterXPath('//form');
431+
432+
$this->assertCount(2, $crawler->filterXPath('attribute::*'));
433+
}
434+
435+
public function testFilterXPathWithChildAxis()
436+
{
437+
$crawler = $this->createTestCrawler()->filterXPath('//body');
438+
439+
$this->assertCount(2, $crawler->filterXPath('child::input'));
440+
}
441+
442+
public function testFilterXPathWithFollowingAxis()
443+
{
444+
$crawler = $this->createTestCrawler()->filterXPath('//a');
445+
446+
$this->assertCount(3, $crawler->filterXPath('following::div'));
447+
}
448+
449+
public function testFilterXPathWithFollowingSiblingAxis()
450+
{
451+
$crawler = $this->createTestCrawler()->filterXPath('//a');
452+
453+
$this->assertCount(2, $crawler->filterXPath('following-sibling::div'));
454+
}
455+
456+
public function testFilterXPathWithParentAxis()
457+
{
458+
$crawler = $this->createTestCrawler()->filterXPath('//button');
459+
460+
$this->assertEquals('foo', $crawler->filterXPath('parent::*')->attr('action'));
461+
}
462+
463+
public function testFilterXPathWithPrecedingAxis()
464+
{
465+
$crawler = $this->createTestCrawler()->filterXPath('//form');
466+
467+
$this->assertCount(13, $crawler->filterXPath('preceding::*'));
468+
}
469+
470+
public function testFilterXPathWithPrecedingSiblingAxis()
471+
{
472+
$crawler = $this->createTestCrawler()->filterXPath('//form');
473+
474+
$this->assertCount(9, $crawler->filterXPath('preceding-sibling::*'));
475+
}
476+
477+
public function testFilterXPathWithSelfAxes()
478+
{
479+
$this->assertCount(1, $this->createTestCrawler()->filterXPath('self::*'));
480+
}
481+
414482
/**
415483
* @covers Symfony\Component\DomCrawler\Crawler::filter
416484
*/

0 commit comments

Comments
 (0)