[DomCrawler] Added support for an automatic default namespace registration.
This commit is contained in:
parent
587e2dd44f
commit
c6fbb13938
@ -577,16 +577,8 @@ class Crawler extends \SplObjectStorage
|
||||
$root->appendChild($document->importNode($node, true));
|
||||
}
|
||||
|
||||
$domxpath = new \DOMXPath($document);
|
||||
if (preg_match_all('/(?P<prefix>[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<prefix>[a-zA-Z_][a-zA-Z_0-9\-\.]+):[^:]/', $xpath, $matches)) {
|
||||
return array_unique($matches['prefix']);
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
Reference in New Issue
Block a user