diff --git a/src/Symfony/Component/DomCrawler/Crawler.php b/src/Symfony/Component/DomCrawler/Crawler.php index 275637a79d..6e63d8ea25 100644 --- a/src/Symfony/Component/DomCrawler/Crawler.php +++ b/src/Symfony/Component/DomCrawler/Crawler.php @@ -577,16 +577,8 @@ class Crawler extends \SplObjectStorage $root->appendChild($document->importNode($node, true)); } - $domxpath = new \DOMXPath($document); - if (preg_match_all('/(?P[a-zA-Z_][a-zA-Z_0-9\-\.]+):[^:]/', $xpath, $matches)) { - foreach ($matches['prefix'] as $prefix) { - // ask for one namespace, otherwise we'd get a collection with an item for each node - $namespaces = $domxpath->query(sprintf('(//namespace::*[name()="%s"])[last()]', $prefix)); - foreach ($namespaces as $node) { - $domxpath->registerNamespace($node->prefix, $node->nodeValue); - } - } - } + $prefixes = $this->findNamespacePrefixes($xpath); + $domxpath = $this->createDOMXPath($document, $prefixes); return new static($domxpath->query($xpath), $this->uri); } @@ -799,4 +791,43 @@ class Crawler extends \SplObjectStorage return $nodes; } + + /** + * @param \DOMDocument $document + * @param array $prefixes + * + * @return \DOMXPath + * + * @throws \InvalidArgumentException + */ + private function createDOMXPath(\DOMDocument $document, array $prefixes = array()) + { + $domxpath = new \DOMXPath($document); + + foreach ($prefixes as $prefix) { + // ask for one namespace, otherwise we'd get a collection with an item for each node + $namespaces = $domxpath->query(sprintf('(//namespace::*[name()="%s"])[last()]', 'default' === $prefix ? '' : $prefix)); + if ($node = $namespaces->item(0)) { + $domxpath->registerNamespace($prefix, $node->nodeValue); + } else { + throw new \InvalidArgumentException(sprintf('Could not find a namespace for the prefix: "%s"', $prefix)); + } + } + + return $domxpath; + } + + /** + * @param $xpath + * + * @return array + */ + private function findNamespacePrefixes($xpath) + { + if (preg_match_all('/(?P[a-zA-Z_][a-zA-Z_0-9\-\.]+):[^:]/', $xpath, $matches)) { + return array_unique($matches['prefix']); + } + + return array(); + } } diff --git a/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php b/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php index 0b20e732fe..cca6165fc2 100644 --- a/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php +++ b/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php @@ -373,7 +373,7 @@ EOF public function testFilterXPathWithDefaultNamespace() { - $crawler = $this->createTestXmlCrawler()->filterXPath('//entry/id'); + $crawler = $this->createTestXmlCrawler()->filterXPath('//default:entry/default:id'); $this->assertCount(1, $crawler, '->filterXPath() automatically registers a namespace'); $this->assertSame('tag:youtube.com,2008:video:kgZRZmEc9j4', $crawler->text()); } @@ -391,6 +391,15 @@ EOF $this->assertSame('widescreen', $crawler->text()); } + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Could not find a namespace for the prefix: "foo" + */ + public function testFilterXPathWithAnInvalidNamespace() + { + $this->createTestXmlCrawler()->filterXPath('//media:group/foo:aspectRatio'); + } + /** * @covers Symfony\Component\DomCrawler\Crawler::filter */ @@ -411,7 +420,7 @@ EOF { $this->markSkippedIfCssSelectorNotPresent(); - $crawler = $this->createTestXmlCrawler()->filter('entry id'); + $crawler = $this->createTestXmlCrawler()->filter('default|entry default|id'); $this->assertCount(1, $crawler, '->filter() automatically registers namespaces'); $this->assertSame('tag:youtube.com,2008:video:kgZRZmEc9j4', $crawler->text()); }