bug #11548 [Component][DomCrawler] fix axes handling in Crawler::filterXPath() (xabbuh)
This PR was merged into the 2.3 branch.
Discussion
----------
[Component][DomCrawler] fix axes handling in Crawler::filterXPath()
| Q | A
| ------------- | ---
| Bug fix? | yes
| New feature? | no
| BC breaks? | no
| Deprecations? | no
| Tests pass? | yes
| Fixed tickets | #11503
| License | MIT
| Doc PR |
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.
The only axis missing after this is the ``namespace`` axis. Filtering for namespace nodes returns ``DOMNameSpaceNode`` instances which can't be passed to the ``add()`` method.
Commits
-------
8dc322b
fix axes handling in Crawler::filterXPath()
This commit is contained in:
commit
9ac2234eb8
@ -854,7 +854,7 @@ class Crawler extends \SplObjectStorage
|
|||||||
$expression = $nonMatchingExpression;
|
$expression = $nonMatchingExpression;
|
||||||
} elseif (0 === strpos($expression, 'descendant::')) {
|
} elseif (0 === strpos($expression, 'descendant::')) {
|
||||||
$expression = 'descendant-or-self::' . substr($expression, strlen('descendant::'));
|
$expression = 'descendant-or-self::' . substr($expression, strlen('descendant::'));
|
||||||
} elseif (0 !== strpos($expression, 'descendant-or-self::')) {
|
} elseif (!preg_match('/^(ancestor|ancestor-or-self|attribute|child|descendant-or-self|following|following-sibling|parent|preceding|preceding-sibling|self)::/', $expression)) {
|
||||||
$expression = 'self::' .$expression;
|
$expression = 'self::' .$expression;
|
||||||
}
|
}
|
||||||
$expressions[] = $parenthesis.$expression;
|
$expressions[] = $parenthesis.$expression;
|
||||||
|
@ -411,6 +411,74 @@ EOF
|
|||||||
$this->assertCount(3, $crawler->filterXPath('//body')->filterXPath('//button')->parents(), '->filterXpath() preserves parents when chained');
|
$this->assertCount(3, $crawler->filterXPath('//body')->filterXPath('//button')->parents(), '->filterXpath() preserves parents when chained');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testFilterXPathWithAncestorAxis()
|
||||||
|
{
|
||||||
|
$crawler = $this->createTestCrawler()->filterXPath('//form');
|
||||||
|
|
||||||
|
$this->assertCount(2, $crawler->filterXPath('ancestor::*'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFilterXPathWithAncestorOrSelfAxis()
|
||||||
|
{
|
||||||
|
$crawler = $this->createTestCrawler()->filterXPath('//form');
|
||||||
|
|
||||||
|
$this->assertCount(3, $crawler->filterXPath('ancestor-or-self::*'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFilterXPathWithAttributeAxis()
|
||||||
|
{
|
||||||
|
$crawler = $this->createTestCrawler()->filterXPath('//form');
|
||||||
|
|
||||||
|
$this->assertCount(2, $crawler->filterXPath('attribute::*'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFilterXPathWithChildAxis()
|
||||||
|
{
|
||||||
|
$crawler = $this->createTestCrawler()->filterXPath('//body');
|
||||||
|
|
||||||
|
$this->assertCount(2, $crawler->filterXPath('child::input'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFilterXPathWithFollowingAxis()
|
||||||
|
{
|
||||||
|
$crawler = $this->createTestCrawler()->filterXPath('//a');
|
||||||
|
|
||||||
|
$this->assertCount(3, $crawler->filterXPath('following::div'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFilterXPathWithFollowingSiblingAxis()
|
||||||
|
{
|
||||||
|
$crawler = $this->createTestCrawler()->filterXPath('//a');
|
||||||
|
|
||||||
|
$this->assertCount(2, $crawler->filterXPath('following-sibling::div'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFilterXPathWithParentAxis()
|
||||||
|
{
|
||||||
|
$crawler = $this->createTestCrawler()->filterXPath('//button');
|
||||||
|
|
||||||
|
$this->assertEquals('foo', $crawler->filterXPath('parent::*')->attr('action'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFilterXPathWithPrecedingAxis()
|
||||||
|
{
|
||||||
|
$crawler = $this->createTestCrawler()->filterXPath('//form');
|
||||||
|
|
||||||
|
$this->assertCount(13, $crawler->filterXPath('preceding::*'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFilterXPathWithPrecedingSiblingAxis()
|
||||||
|
{
|
||||||
|
$crawler = $this->createTestCrawler()->filterXPath('//form');
|
||||||
|
|
||||||
|
$this->assertCount(9, $crawler->filterXPath('preceding-sibling::*'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFilterXPathWithSelfAxes()
|
||||||
|
{
|
||||||
|
$this->assertCount(1, $this->createTestCrawler()->filterXPath('self::*'));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @covers Symfony\Component\DomCrawler\Crawler::filter
|
* @covers Symfony\Component\DomCrawler\Crawler::filter
|
||||||
*/
|
*/
|
||||||
|
Reference in New Issue
Block a user