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:
Fabien Potencier 2014-08-03 08:32:28 +02:00
commit 9ac2234eb8
2 changed files with 69 additions and 1 deletions

View File

@ -854,7 +854,7 @@ class Crawler extends \SplObjectStorage
$expression = $nonMatchingExpression;
} elseif (0 === strpos($expression, '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;
}
$expressions[] = $parenthesis.$expression;

View File

@ -411,6 +411,74 @@ EOF
$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
*/