关于问题的说明以及与 PHP 缺乏片段命名空间资源的关系。
PHP 错误?
(在@slapyo 之后)
有一个PHP bug#44773: 不是“好行为”,是一个错误(!)。如果您同意,请在此处添加评论,并在此处投票(!)。
假设您使用replace_innerXML($node,$innerXML) 函数或任何其他类似的上下文...请参阅下面的“典型场景”部分。
如何解决?
如果没有大的正则表达式(在示例中超过 $innerXML)和缓慢的算法,设置每个标签而不需要命名空间声明......当然,毕竟,appendXML() 将片段变成树的组件,所以不需要命名空间,因为它已经在根...所有工作只是使用错误片段的appendXML()。
典型场景
(在@ThW 回答/讨论之后)典型的“盲命名空间”片段使用。
当片段是具有新命名空间的“外部”时,好的,片段需要自己声明使用的命名空间......但是这个问题中暴露的问题不是这个异国情调,而是一个如此常见的另一个.
PS:正如我们将要看到的,“PHP bug”解决方案也是针对这种情况的解决方案。
在这里,为了说明,片段有两种典型用途不存在关于命名空间(由片段的元素使用)的先验知识,只有所有已在 DOMDocument 中声明(无需重新声明)。
1) 一个XSLT call-to-PHP-returning-fragment by XSLTProcessor::registerPHPFunctions();
2) 一个“通用 DOM 库”,它提供一种处理方法,用于将节点的 XML 内部内容替换为新的 XML 内容,该内容可以是片段内容。请参阅下面的函数replace_innerXML()。
function replace_innerXML(DOMNode $e, $innerXML='') {
if ($e && ($innerXML>'' || $e->nodeValue>'')) {
$e->nodeValue='';
if ($innerXML>'') {
$tmp = $e->ownerDocument->createDocumentFragment();
// HERE we need to INJECT namespace declarations into $innerXML
$tmp->appendXML($innerXML);
$e->appendChild( $tmp );
}
return true;
}
return false;
}
// This function is only illustrative, for other propuses
// see https://stackoverflow.com/q/26029868/287948
// Example of use:
$innerXML='nonoo <xx xx:aa="ww">uuu</xx> nono<a:yy zz:href="...">uu</a:yy>...';
replace_innerXML($someNode,$innerXML);
如果提供 PHP 功能,“到 INJECT 命名空间”的算法(见函数中的注释)会很简单......但是,正如we insist,PHP 有一个错误,因为什么都不提供(!).
一个巨大的解决方案
“INJECT 命名空间”的唯一方法(今天是 2014 年)是
$innerXML = preg_replace_callback(
"/([<\s])($namespacesJoinByPipe):([^\s>]+)/s",
function ($m) use($namespacesAssociative) {
$nsdecl = "xmlns:$m[2]=\"".$namespacesAssociative[$m[2]].'"';
return ($m[1]=='<')
? "<$m[1]$m[2]:$m[3] $nsdecl " // tag like "<a:yy"
: " $nsdecl $m[1]$m[2]:$m[3]"; // attribute like " xx:aa"
},
$innerXML
);
...所以,做这么简单的事情是一件大事:只接受预先存在的 DOMDocument 命名空间。
PHP有一个bug是因为没有避开这个“大象”...解决“PHP bug”的解决方案?
PHP的理想解决方案
PHP RCF to solve the problem 有许多替代方案:标志 createDocumentFragment($importRootNamespaces=false)、引用节点 createDocumentFragment($refNamespacesNode=NULL) 或 DOMDocumentFragment::setAttributeNS() method... 所有的默认行为都等同于通常的 createDocumentFragment()(无参数)。
PS:这些解决方案中的任何一个也有助于处理其他问题,例如第一个评论,“......当片段是具有新命名空间的'外部'时......”。