From 9110468e9982f825cd5a3941f31f6028effcd5ec Mon Sep 17 00:00:00 2001 From: Jakub Zalas Date: Sun, 22 Sep 2013 23:29:38 +0100 Subject: [PATCH] [DomCrawler] Enabled manual namespace registration. --- src/Symfony/Component/DomCrawler/CHANGELOG.md | 6 ++- src/Symfony/Component/DomCrawler/Crawler.php | 47 ++++++++++++++++--- .../DomCrawler/Tests/CrawlerTest.php | 12 ++++- 3 files changed, 55 insertions(+), 10 deletions(-) diff --git a/src/Symfony/Component/DomCrawler/CHANGELOG.md b/src/Symfony/Component/DomCrawler/CHANGELOG.md index 06ed6c000b..66ce6542c4 100644 --- a/src/Symfony/Component/DomCrawler/CHANGELOG.md +++ b/src/Symfony/Component/DomCrawler/CHANGELOG.md @@ -4,9 +4,11 @@ CHANGELOG 2.4.0 ----- - * added auto-registration of document namespaces for `Crawler::filterXPath()` and `Crawler::filter()` + * added support for automatic discovery and explicit registration of document + namespaces for `Crawler::filterXPath()` and `Crawler::filter()` * improved content type guessing in `Crawler::addContent()` - * [BC BREAK] `Crawler::addXmlContent()` no longer removes the default document namespace + * [BC BREAK] `Crawler::addXmlContent()` no longer removes the default document + namespace 2.3.0 ----- diff --git a/src/Symfony/Component/DomCrawler/Crawler.php b/src/Symfony/Component/DomCrawler/Crawler.php index 790d86a75a..2935a51f53 100644 --- a/src/Symfony/Component/DomCrawler/Crawler.php +++ b/src/Symfony/Component/DomCrawler/Crawler.php @@ -32,6 +32,11 @@ class Crawler extends \SplObjectStorage */ private $defaultNamespacePrefix = 'default'; + /** + * @var array A map of manually registered namespaces + */ + private $namespaces = array(); + /** * Constructor. * @@ -723,6 +728,15 @@ class Crawler extends \SplObjectStorage $this->defaultNamespacePrefix = $prefix; } + /** + * @param string $prefix + * @param string $namespace + */ + public function registerNamespace($prefix, $namespace) + { + $this->namespaces[$prefix] = $namespace; + } + /** * Converts string for XPath expressions. * @@ -820,18 +834,37 @@ class Crawler extends \SplObjectStorage $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()]', $this->defaultNamespacePrefix === $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)); - } + $namespace = $this->discoverNamespace($domxpath, $prefix); + $domxpath->registerNamespace($prefix, $namespace); } return $domxpath; } + /** + * @param \DOMXPath $domxpath + * @param string $prefix + * + * @return string + * + * @throws \InvalidArgumentException + */ + private function discoverNamespace(\DOMXPath $domxpath, $prefix) + { + if (isset($this->namespaces[$prefix])) { + return $this->namespaces[$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()]', $this->defaultNamespacePrefix === $prefix ? '' : $prefix)); + + if ($node = $namespaces->item(0)) { + return $node->nodeValue; + } + + throw new \InvalidArgumentException(sprintf('Could not find a namespace for the prefix: "%s"', $prefix)); + } + /** * @param $xpath * diff --git a/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php b/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php index 54760b7bed..9995b8ffe4 100644 --- a/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php +++ b/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php @@ -384,7 +384,7 @@ EOF $crawler->setDefaultNamespacePrefix('x'); $crawler = $crawler->filterXPath('//x:entry/x:id'); - $this->assertCount(1, $crawler, '->filterXPath() automatically registers a namespace'); + $this->assertCount(1, $crawler, '->filterXPath() lets to override the default namespace prefix'); $this->assertSame('tag:youtube.com,2008:video:kgZRZmEc9j4', $crawler->text()); } @@ -410,6 +410,16 @@ EOF $this->createTestXmlCrawler()->filterXPath('//media:group/foo:aspectRatio'); } + public function testFilterXPathWithManuallyRegisteredNamespace() + { + $crawler = $this->createTestXmlCrawler(); + $crawler->registerNamespace('m', 'http://search.yahoo.com/mrss/'); + + $crawler = $crawler->filterXPath('//m:group/yt:aspectRatio'); + $this->assertCount(1, $crawler, '->filterXPath() uses manually registered namespace'); + $this->assertSame('widescreen', $crawler->text()); + } + /** * @covers Symfony\Component\DomCrawler\Crawler::filter */