NOTES about the question and the relation with PHP lack of resources for fragment namespaces.
A PHP bug?
(after @slapyo)
There are a PHP bug#44773: is not a "good behaviour", is a bug (!). If you agree please add a comment there, and vote up here (!).
Imagine you using a replace_innerXML($node,$innerXML)
function, or any other similar context... See "typical scenarios" section below.
How to workaround?
Without a big regular expression (over $innerXML
in the example) and slow algorithm, to set each tag without a namespace declaration... And, of course, after all, the appendXML()
turns the fragment a component of the tree, so no namespace is need because it is already at the root... all work is only to use the buggy fragments's appendXML()
.
Typical scenarios
(after @ThW answer/discussion) Typical "blind namespace" fragment uses.
When the fragment is a "extraterrenal" with a new namespace, ok, the fragment need to declare by itself the used namespaces... But the problem exposed in this question IS NOT this exotic one, is a so commom other one.
PS: as we will se, the "PHP bug"-solution also is a solution to this context.
Here, to illustrate, there are two typical uses of fragments where no a priori knowledge about namespaces (used by of fragment's elements) exist, only the fact that all have been declared in the DOMDocument (not need to redeclare).
1) a XSLT call-to-PHP-returning-fragment by XSLTProcessor::registerPHPFunctions()
;
2) a "generic DOM library" that offer a handling method for replace the XML inner contents of a node by a new XML content, that can be a fragment-content. See function replace_innerXML()
below.
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);
The algorithm "to INJECT namespace" (see comment in the function) would be simple if PHP features offered ... But, as we insist, PHP have a bug because offers nothing (!).
An elephantic solution
The only way (today 2014) to "INJECT namespace" is
$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
);
... So, is a big elephant to do a so simple thing: only to accept the pre-existent DOMDocument namespaces.
PHP have a bug because not avoid this "big elephant"... Solution to solve the "PHP bug"?
PHP's ideal solution
There are many alternatives for a PHP RCF to solve the problem: a flag createDocumentFragment($importRootNamespaces=false)
, a reference node createDocumentFragment($refNamespacesNode=NULL)
, or a DOMDocumentFragment::setAttributeNS() method
... All with a default behaviour equivalent to usual createDocumentFragment()
(no parameter).
PS: any of these solutions also help to handle other problems, like the first one comented, "... when the fragment is a 'extraterrenal' with a new namespace ...".