A problem occurs when the XML document you want to parse does not declare a namespace consistently; sometimes it does declare the namespace, sometimes not.
Your XPath queries will fail if you use the ns prefix in your query while it is not declared in the XML (resulting in this error: "SimpleXMLElement::xpath() [simplexmlelement.xpath]: Undefined namespace prefix"). On the other hand the query will also fail if you don't use the prefix if the namespace is declared in the XML (will return an empty result).
Since you can only register a namespace prefix for XPath if the namespace is declared (registerXPathNamespace()), the only way to cope with this, is to write the prefix in your XPath queries with a little variable.
eg.
<?php
// get used namespaces
$namespaces = $this->simple_xml->getNamespaces(TRUE);
// say namespace 'pre:' is not defined consistently
// define namespace prefix var for xpath queries
$this->ns_prefix = isset($namespaces['pre']) ? 'pre:' : '';
// your xpath queries look like this (section/pre:value or section/value)
$res = $this->simple_xml->xpath('section/'. $this->ns_prefix .'value');
?>
It is not an elegant solution but it I couldn't find a better one. (Add a registerNamespace($prefix, $url) method? ;))
SimpleXMLElement->registerXPathNamespace()
(PHP 5 >= 5.2.0)
SimpleXMLElement->registerXPathNamespace() — Cria um prefixo/namespace de contexto para a próxima consulta XPath
Descrição
Cria um prefixo/namespace de contexto para a próxima consulta XPath. Basicamente, esta função auxilia se o provedor do documentl XML altera os prefixos dos namespaces. registerXPathNamespace criará um prefixo para o namespace associado, fazendo com que se possa acessar os namespaces sem ser necessário modificar o código para entrar em conformidade com os novos prefixos ditados pelo provedor dos dados.
Parâmetros
- prefix
-
O prefixo do namespace utilizado na consulta XPath para o namespace dado em ns .
- ns
-
O namespace para ser utilizado na consulta XPath. Este parâmetro deve fechar com um namespace utilizado pelo documento XML ou a consulta XPath utilizando prefix não retornará nenhum resultado.
Valor Retornado
Retorna TRUE em caso de sucesso ou FALSE em falhas.
Exemplos
Exemplo #1 Definindo um prefixo de namespace para ser usado em uma consulta XPath
<?php
$xml = <<<EOD
<book xmlns:chap="http://example.org/chapter-title">
<title>My Book</title>
<chapter id="1">
<chap:title>Chapter 1</chap:title>
<para>Donec velit. Nullam eget tellus vitae tortor gravida scelerisque.
In orci lorem, cursus imperdiet, ultricies non, hendrerit et, orci.
Nulla facilisi. Nullam velit nisl, laoreet id, condimentum ut,
ultricies id, mauris.</para>
</chapter>
<chapter id="2">
<chap:title>Chapter 2</chap:title>
<para>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin
gravida. Phasellus tincidunt massa vel urna. Proin adipiscing quam
vitae odio. Sed dictum. Ut tincidunt lorem ac lorem. Duis eros
tellus, pharetra id, faucibus eu, dapibus dictum, odio.</para>
</chapter>
</book>
EOD;
$sxe = new SimpleXMLElement($xml);
$sxe->registerXPathNamespace('c', 'http://example.org/chapter-title');
$result = $sxe->xpath('//c:title');
foreach ($result as $title) {
echo $title . "\n";
}
?>
Perceba como como o documento XML mostrado no exemplo define o namespace com o prefixo de chap. Imagine que este documento (ou outro semelhante) deveria ter utilizado o prefixo de c no passado para o mesmo namespace. Uma vez que ele foi alterado, a consulta XPath não irá mais retornar os resultados apropriados e a consulta exigirá modificações. Utilizando registerXPathNamespace evita modificações futuras na consulta, mesmo que o provedor altere o prefixo dos namespaces.
SimpleXMLElement->registerXPathNamespace()
10-Jul-2009 09:18
16-Jan-2009 11:28
Registering xpath-namespaces is mandatory when your input xml has a default namespace.
Unfortunately an empty prefix '' cannot be registered, I use 'default' as prefix:
<?php
$sxe->registerXPathNamespace('default', 'mynamespace');
// then
$sxe->xpath('//default:nodename');
?>
Bad news is that xpath-namespaces must be registered on EVERY SimpleXMLElement on which ->xpath() is to be called! (registering it on root node is not sufficient)
30-Jul-2008 10:45
A handy timesaver:
<?php
$sxe = simplexml_load_file($path);
//Fetch all namespaces
$namespaces = $sxe->getNamespaces(true);
//Register them with their prefixes
foreach ($namespaces as $prefix => $ns) {
$sxe->registerXPathNamespace($prefix, $ns);
}
?>

SimpleXMLElement->getNamespaces()