Skip to content

Commit 43a7716

Browse files
committed
[DomCrawler] Fixed filterXPath() chaining
1 parent e453c45 commit 43a7716

File tree

4 files changed

+20
-34
lines changed

4 files changed

+20
-34
lines changed

src/Symfony/Component/DomCrawler/Crawler.php

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,7 @@ public function parents()
441441
$nodes = array();
442442

443443
while ($node = $node->parentNode) {
444-
if (1 === $node->nodeType && '_root' !== $node->nodeName) {
444+
if (1 === $node->nodeType) {
445445
$nodes[] = $node;
446446
}
447447
}
@@ -584,15 +584,13 @@ public function extract($attributes)
584584
*/
585585
public function filterXPath($xpath)
586586
{
587-
$document = new \DOMDocument('1.0', 'UTF-8');
588-
$root = $document->appendChild($document->createElement('_root'));
587+
$crawler = new static(null, $this->uri);
589588
foreach ($this as $node) {
590-
$root->appendChild($document->importNode($node, true));
589+
$domxpath = new \DOMXPath($node->ownerDocument);
590+
$crawler->add($domxpath->query($xpath, $node));
591591
}
592592

593-
$domxpath = new \DOMXPath($document);
594-
595-
return new static($domxpath->query($xpath), $this->uri);
593+
return $crawler;
596594
}
597595

598596
/**

src/Symfony/Component/DomCrawler/Field/FormField.php

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,7 @@ public function __construct(\DOMNode $node)
5252
{
5353
$this->node = $node;
5454
$this->name = $node->getAttribute('name');
55-
56-
$this->document = new \DOMDocument('1.0', 'UTF-8');
57-
$this->node = $this->document->importNode($this->node, true);
58-
59-
$root = $this->document->appendChild($this->document->createElement('_root'));
60-
$root->appendChild($this->node);
61-
$this->xpath = new \DOMXPath($this->document);
55+
$this->xpath = new \DOMXPath($node->ownerDocument);
6256

6357
$this->initialize();
6458
}

src/Symfony/Component/DomCrawler/Form.php

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -378,9 +378,7 @@ private function initialize()
378378
{
379379
$this->fields = new FormFieldRegistry();
380380

381-
$document = new \DOMDocument('1.0', 'UTF-8');
382-
$xpath = new \DOMXPath($document);
383-
$root = $document->appendChild($document->createElement('_root'));
381+
$xpath = new \DOMXPath($this->node->ownerDocument);
384382

385383
// add submitted button if it has a valid name
386384
if ('form' !== $this->button->nodeName && $this->button->hasAttribute('name') && $this->button->getAttribute('name')) {
@@ -390,39 +388,33 @@ private function initialize()
390388

391389
// temporarily change the name of the input node for the x coordinate
392390
$this->button->setAttribute('name', $name.'.x');
393-
$this->set(new Field\InputFormField($document->importNode($this->button, true)));
391+
$this->set(new Field\InputFormField($this->button));
394392

395393
// temporarily change the name of the input node for the y coordinate
396394
$this->button->setAttribute('name', $name.'.y');
397-
$this->set(new Field\InputFormField($document->importNode($this->button, true)));
395+
$this->set(new Field\InputFormField($this->button));
398396

399397
// restore the original name of the input node
400398
$this->button->setAttribute('name', $name);
401-
}
402-
else {
403-
$this->set(new Field\InputFormField($document->importNode($this->button, true)));
399+
} else {
400+
$this->set(new Field\InputFormField($this->button));
404401
}
405402
}
406403

407404
// find form elements corresponding to the current form
408405
if ($this->node->hasAttribute('id')) {
409-
// traverse through the whole document
410-
$node = $document->importNode($this->node->ownerDocument->documentElement, true);
411-
$root->appendChild($node);
412-
413406
// corresponding elements are either descendants or have a matching HTML5 form attribute
414407
$formId = Crawler::xpathLiteral($this->node->getAttribute('id'));
415-
$fieldNodes = $xpath->query(sprintf('descendant::input[@form=%s] | descendant::button[@form=%s] | descendant::textarea[@form=%s] | descendant::select[@form=%s] | //form[@id=%s]//input[not(@form)] | //form[@id=%s]//button[not(@form)] | //form[@id=%s]//textarea[not(@form)] | //form[@id=%s]//select[not(@form)]', $formId, $formId, $formId, $formId, $formId, $formId, $formId, $formId), $root);
408+
409+
// do the xpath query without $this->node as the context node (i.e. traverse through the whole document)
410+
$fieldNodes = $xpath->query(sprintf('descendant::input[@form=%s] | descendant::button[@form=%s] | descendant::textarea[@form=%s] | descendant::select[@form=%s] | //form[@id=%s]//input[not(@form)] | //form[@id=%s]//button[not(@form)] | //form[@id=%s]//textarea[not(@form)] | //form[@id=%s]//select[not(@form)]', $formId, $formId, $formId, $formId, $formId, $formId, $formId, $formId));
416411
foreach ($fieldNodes as $node) {
417412
$this->addField($node);
418413
}
419414
} else {
420-
// parent form has no id, add descendant elements only
421-
$node = $document->importNode($this->node, true);
422-
$root->appendChild($node);
423-
424-
// descendant elements with form attribute are not part of this form
425-
$fieldNodes = $xpath->query('descendant::input[not(@form)] | descendant::button[not(@form)] | descendant::textarea[not(@form)] | descendant::select[not(@form)]', $root);
415+
// do the xpath query with $this->node as the context node, to only find descendant elements
416+
// however, descendant elements with form attribute are not part of this form
417+
$fieldNodes = $xpath->query('descendant::input[not(@form)] | descendant::button[not(@form)] | descendant::textarea[not(@form)] | descendant::select[not(@form)]', $this->node);
426418
foreach ($fieldNodes as $node) {
427419
$this->addField($node);
428420
}

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,8 +378,10 @@ public function testFilterXPath()
378378
$this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->filterXPath() returns a new instance of a crawler');
379379

380380
$crawler = $this->createTestCrawler()->filterXPath('//ul');
381-
382381
$this->assertCount(6, $crawler->filterXPath('//li'), '->filterXPath() filters the node list with the XPath expression');
382+
383+
$crawler = $this->createTestCrawler();
384+
$this->assertCount(3, $crawler->filterXPath('//body')->filterXPath('//button')->parents(), '->filterXpath() preserves parents when chained');
383385
}
384386

385387
/**

0 commit comments

Comments
 (0)