我有一个XML文档,如下所示:
<Data
xmlns="http://www.domain.com/schema/data"
xmlns:dmd="http://www.domain.com/schema/data-metadata"
>
<Something>...</Something>
</Data>
我正在使用PHP中的SimpleXML解析信息。我正在处理数组,我似乎遇到了命名空间的问题。
我的问题是:如何删除这些命名空间?我从XML文件中读取数据。
谢谢!
答案 0 :(得分:16)
如果你正在使用XPath,那么它是XPath的限制而不是 PHP会在xpath and default namespaces上查看此解释以获取更多信息。
更具体地说,它是根节点中导致问题的xmlns=""
属性。这意味着您需要注册命名空间,然后使用QName来引用元素。
$feed = simplexml_load_file('http://www.sitepoint.com/recent.rdf');
$feed->registerXPathNamespace("a", "http://www.domain.com/schema/data");
$result = $feed->xpath("a:Data/a:Something/...");
重要:registerXPathNamespace
调用中使用的URI必须与实际XML文件中使用的URI相同。
答案 1 :(得分:13)
我发现上面的答案很有帮助,但它对我来说并不适用。 最终效果更好:
// Gets rid of all namespace definitions
$xml_string = preg_replace('/xmlns[^=]*="[^"]*"/i', '', $xml_string);
// Gets rid of all namespace references
$xml_string = preg_replace('/[a-zA-Z]+:([a-zA-Z]+[=>])/', '$1', $xml_string);
答案 2 :(得分:1)
以下PHP代码会自动检测别名“default”下XML文件中指定的默认命名空间。不必更新所有xpath查询以包含前缀default:
因此,如果您想要读取XML文件,而不是它们包含默认的NS定义,或者它们没有,并且您想查询所有Something
元素,则可以使用以下代码:
$xml = simplexml_load_file($name);
$namespaces = $xml->getDocNamespaces();
if (isset($namespaces[''])) {
$defaultNamespaceUrl = $namespaces[''];
$xml->registerXPathNamespace('default', $defaultNamespaceUrl);
$nsprefix = 'default:';
} else {
$nsprefix = '';
}
$somethings = $xml->xpath('//'.$nsprefix.'Something');
echo count($somethings).' times found';
答案 3 :(得分:0)
要完全删除命名空间,您需要使用正则表达式(RegEx)。例如:
$feed = file_get_contents("http://www.sitepoint.com/recent.rdf");
$feed = preg_replace("/<.*(xmlns *= *[\"'].[^\"']*[\"']).[^>]*>/i", "", $feed); // This removes ALL default namespaces.
$xml_feed = simplexml_load_string($feed);
然后你在加载XML之前剥离了任何xml命名空间(小心使用正则表达式,因为如果你有任何字段有类似的东西:
<![CDATA[ <Transfer xmlns="http://redeux.example.com">cool.</Transfer> ]]>
然后它将从CDATA内部剥离xmlns,这可能会导致意外结果。
答案 4 :(得分:0)
当您只想使用解析的 xml 并且不关心任何命名空间时, 你只需删除它们。正则表达式很好,而且比我下面的方法快得多。
但是为了在删除命名空间时更安全的方法,可以使用 SimpleXML 解析 xml 并询问它具有的命名空间,如下所示:
$xml = '...';
$namespaces = simplexml_load_string($xml)->getDocNamespaces(true);
//The line bellow fetches default namespace with empty key, like this: '' => 'url'
//So we remove any default namespace from the array
$namespaces = array_filter(array_keys($namespaces), function($k){return !empty($k);});
$namespaces = array_map(function($ns){return "$ns:";}, $namespaces);
$ns_clean_xml = str_replace("xmlns=", "ns=", $xml);
$ns_clean_xml = str_replace($namespaces, array_fill(0, count($namespaces), ''), $ns_clean_xml);
$xml_obj = simplexml_load_string($ns_clean_xml);
因此,您只为命名空间点击替换,避免删除 xml 可能具有的任何其他内容。
其实我是用它作为一种方法:
function refined_simplexml_load_string($xml_string) {
if(false === ($x1 = simplexml_load_string($xml_string)) ) return false;
$namespaces = array_keys($x1->getDocNamespaces(true));
$namespaces = array_filter($namespaces, function($k){return !empty($k);});
$namespaces = array_map(function($ns){return "$ns:";}, $namespaces);
return simplexml_load_string($ns_clean_xml = str_replace(
array_merge(["xmlns="], $namespaces),
array_merge(["ns="], array_fill(0, count($namespaces), '')),
$xml_string
));
}