一个简单的DOMDocument,并附加两个子节点,一个不带子节点,一个附加默认名称空间:
$dom = new DOMDocument();
$dom->loadXML('<list/></list>');
$dom->formatOutput = true;
$docX = new DOMDocument();
$docX->loadXML('<item><one>bar</one></item>');
$dom->documentElement->appendChild($dom->importNode($docX->documentElement, true));
print($dom->saveXML()); // OK
$docY = new DOMDocument();
$docY->loadXML('<item><two xmlns="xxx:yyy">tar</two></item>');
$dom->documentElement->appendChild($dom->importNode($docY->documentElement, true));
print($dom->saveXML()); // Not OK
添加没有xmlns
属性的子节点可以正常工作:
<?xml version="1.0"?>
<list>
<item>
<one>bar</one>
</item>
</list>
在添加具有默认名称空间(即xmlns
属性)的子节点时,PHP为该名称空间添加别名default
:
<?xml version="1.0"?>
<list>
...
<item xmlns:default="xxx:yyy">
<default:two xmlns="xxx:yyy">tar</default:two>
</item>
</list>
我用PHP编写15年以上从未见过。有建议的解决方法来避免这种行为吗?
在一个更为复杂的场景中,我尝试在调用appendChild()
之后将该前缀简单地设置为null,但是它会抛出一条神秘的DOMException: Namespace Error
消息。这个简化的示例没有执行此操作,而是生成了以下XML:
<?xml version="1.0"?>
<list>
...
<item xmlns:default="xxx:yyy">
<:two xmlns="xxx:yyy" xmlns:="xxx:yyy">tar</:two>
</item>
</list>
作为添加子项后的解决方法,我将其克隆,以删除进程中的所有前缀名称空间,删除原始子项,而是添加克隆项(没有default
前缀),然后在以下位置重新添加前缀:
function stripNamespace($dom, $target) {
$clone = $dom->createElement(preg_replace('`.*:`', '', $target->nodeName));
foreach ($target->attributes as $v)
$clone->setAttribute($v->nodeName, $v->value);
foreach ($target->childNodes as $child)
$clone->appendChild(
$child->nodeName == "#text" ?
$dom->createTextNode($child->nodeValue) :
$this->stripNamespace($dom, $child)
);
return $clone;
}
有没有那么麻烦的处理方式?