在添加具有默认名称空间的子代时如何防止前缀“默认”?

时间:2019-04-15 15:35:55

标签: php xml dom appendchild

一个简单的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;
}

有没有那么麻烦的处理方式?

0 个答案:

没有答案