繁体   English   中英

使用 PHP 从 XML 中删除命名空间

[英]Remove namespace from XML using PHP

我有一个如下所示的 XML 文档:

<Data 
  xmlns="http://www.domain.com/schema/data" 
  xmlns:dmd="http://www.domain.com/schema/data-metadata"
>
  <Something>...</Something>
</Data>

我正在使用 PHP 中的 SimpleXML 解析信息。 我正在处理数组,但命名空间似乎有问题。

我的问题是:如何删除这些命名空间? 我从 XML 文件中读取数据。

谢谢!

如果您使用的是 XPath,那么它是 XPath 的限制,而不是PHP,请查看有关xpath 和默认命名空间的解释以获取更多信息。

更具体地说,它是导致问题的根节点中的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 相同。

我发现上面的答案很有帮助,但对我来说并不奏效。 这最终效果更好:

// 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);

以下 PHP 代码自动检测 XML 文件中别名“default”下指定的默认命名空间。 不必更新所有 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';

要完全删除命名空间,您需要使用正则表达式 (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,这可能会导致意外结果。

当您只想使用解析的 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
  ));
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM