[DomCrawler] Fixed filterXPath() chaining
This commit is contained in:
parent
e453c4589d
commit
43a771614c
@ -441,7 +441,7 @@ class Crawler extends \SplObjectStorage
|
|||||||
$nodes = array();
|
$nodes = array();
|
||||||
|
|
||||||
while ($node = $node->parentNode) {
|
while ($node = $node->parentNode) {
|
||||||
if (1 === $node->nodeType && '_root' !== $node->nodeName) {
|
if (1 === $node->nodeType) {
|
||||||
$nodes[] = $node;
|
$nodes[] = $node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -584,15 +584,13 @@ class Crawler extends \SplObjectStorage
|
|||||||
*/
|
*/
|
||||||
public function filterXPath($xpath)
|
public function filterXPath($xpath)
|
||||||
{
|
{
|
||||||
$document = new \DOMDocument('1.0', 'UTF-8');
|
$crawler = new static(null, $this->uri);
|
||||||
$root = $document->appendChild($document->createElement('_root'));
|
|
||||||
foreach ($this as $node) {
|
foreach ($this as $node) {
|
||||||
$root->appendChild($document->importNode($node, true));
|
$domxpath = new \DOMXPath($node->ownerDocument);
|
||||||
|
$crawler->add($domxpath->query($xpath, $node));
|
||||||
}
|
}
|
||||||
|
|
||||||
$domxpath = new \DOMXPath($document);
|
return $crawler;
|
||||||
|
|
||||||
return new static($domxpath->query($xpath), $this->uri);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -52,13 +52,7 @@ abstract class FormField
|
|||||||
{
|
{
|
||||||
$this->node = $node;
|
$this->node = $node;
|
||||||
$this->name = $node->getAttribute('name');
|
$this->name = $node->getAttribute('name');
|
||||||
|
$this->xpath = new \DOMXPath($node->ownerDocument);
|
||||||
$this->document = new \DOMDocument('1.0', 'UTF-8');
|
|
||||||
$this->node = $this->document->importNode($this->node, true);
|
|
||||||
|
|
||||||
$root = $this->document->appendChild($this->document->createElement('_root'));
|
|
||||||
$root->appendChild($this->node);
|
|
||||||
$this->xpath = new \DOMXPath($this->document);
|
|
||||||
|
|
||||||
$this->initialize();
|
$this->initialize();
|
||||||
}
|
}
|
||||||
|
@ -378,9 +378,7 @@ class Form extends Link implements \ArrayAccess
|
|||||||
{
|
{
|
||||||
$this->fields = new FormFieldRegistry();
|
$this->fields = new FormFieldRegistry();
|
||||||
|
|
||||||
$document = new \DOMDocument('1.0', 'UTF-8');
|
$xpath = new \DOMXPath($this->node->ownerDocument);
|
||||||
$xpath = new \DOMXPath($document);
|
|
||||||
$root = $document->appendChild($document->createElement('_root'));
|
|
||||||
|
|
||||||
// add submitted button if it has a valid name
|
// add submitted button if it has a valid name
|
||||||
if ('form' !== $this->button->nodeName && $this->button->hasAttribute('name') && $this->button->getAttribute('name')) {
|
if ('form' !== $this->button->nodeName && $this->button->hasAttribute('name') && $this->button->getAttribute('name')) {
|
||||||
@ -390,39 +388,33 @@ class Form extends Link implements \ArrayAccess
|
|||||||
|
|
||||||
// temporarily change the name of the input node for the x coordinate
|
// temporarily change the name of the input node for the x coordinate
|
||||||
$this->button->setAttribute('name', $name.'.x');
|
$this->button->setAttribute('name', $name.'.x');
|
||||||
$this->set(new Field\InputFormField($document->importNode($this->button, true)));
|
$this->set(new Field\InputFormField($this->button));
|
||||||
|
|
||||||
// temporarily change the name of the input node for the y coordinate
|
// temporarily change the name of the input node for the y coordinate
|
||||||
$this->button->setAttribute('name', $name.'.y');
|
$this->button->setAttribute('name', $name.'.y');
|
||||||
$this->set(new Field\InputFormField($document->importNode($this->button, true)));
|
$this->set(new Field\InputFormField($this->button));
|
||||||
|
|
||||||
// restore the original name of the input node
|
// restore the original name of the input node
|
||||||
$this->button->setAttribute('name', $name);
|
$this->button->setAttribute('name', $name);
|
||||||
}
|
} else {
|
||||||
else {
|
$this->set(new Field\InputFormField($this->button));
|
||||||
$this->set(new Field\InputFormField($document->importNode($this->button, true)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// find form elements corresponding to the current form
|
// find form elements corresponding to the current form
|
||||||
if ($this->node->hasAttribute('id')) {
|
if ($this->node->hasAttribute('id')) {
|
||||||
// traverse through the whole document
|
|
||||||
$node = $document->importNode($this->node->ownerDocument->documentElement, true);
|
|
||||||
$root->appendChild($node);
|
|
||||||
|
|
||||||
// corresponding elements are either descendants or have a matching HTML5 form attribute
|
// corresponding elements are either descendants or have a matching HTML5 form attribute
|
||||||
$formId = Crawler::xpathLiteral($this->node->getAttribute('id'));
|
$formId = Crawler::xpathLiteral($this->node->getAttribute('id'));
|
||||||
$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);
|
|
||||||
|
// do the xpath query without $this->node as the context node (i.e. traverse through the whole document)
|
||||||
|
$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));
|
||||||
foreach ($fieldNodes as $node) {
|
foreach ($fieldNodes as $node) {
|
||||||
$this->addField($node);
|
$this->addField($node);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// parent form has no id, add descendant elements only
|
// do the xpath query with $this->node as the context node, to only find descendant elements
|
||||||
$node = $document->importNode($this->node, true);
|
// however, descendant elements with form attribute are not part of this form
|
||||||
$root->appendChild($node);
|
$fieldNodes = $xpath->query('descendant::input[not(@form)] | descendant::button[not(@form)] | descendant::textarea[not(@form)] | descendant::select[not(@form)]', $this->node);
|
||||||
|
|
||||||
// descendant elements with form attribute are not part of this form
|
|
||||||
$fieldNodes = $xpath->query('descendant::input[not(@form)] | descendant::button[not(@form)] | descendant::textarea[not(@form)] | descendant::select[not(@form)]', $root);
|
|
||||||
foreach ($fieldNodes as $node) {
|
foreach ($fieldNodes as $node) {
|
||||||
$this->addField($node);
|
$this->addField($node);
|
||||||
}
|
}
|
||||||
|
@ -378,8 +378,10 @@ EOF
|
|||||||
$this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->filterXPath() returns a new instance of a crawler');
|
$this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->filterXPath() returns a new instance of a crawler');
|
||||||
|
|
||||||
$crawler = $this->createTestCrawler()->filterXPath('//ul');
|
$crawler = $this->createTestCrawler()->filterXPath('//ul');
|
||||||
|
|
||||||
$this->assertCount(6, $crawler->filterXPath('//li'), '->filterXPath() filters the node list with the XPath expression');
|
$this->assertCount(6, $crawler->filterXPath('//li'), '->filterXPath() filters the node list with the XPath expression');
|
||||||
|
|
||||||
|
$crawler = $this->createTestCrawler();
|
||||||
|
$this->assertCount(3, $crawler->filterXPath('//body')->filterXPath('//button')->parents(), '->filterXpath() preserves parents when chained');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user