PHP中向DOM追加子节点时冗余命名空间前缀问题解决方法
解决PHP中XML片段追加时的冗余命名空间前缀问题
问题原因
你遇到的冗余xmlns:default属性和default前缀,是PHP DOMDocument在导入带命名空间的XML节点时的自动行为:当导入的子节点属于某个未在父节点上下文声明的命名空间时,DOM会自动将命名空间声明提升到父节点,并分配默认前缀来保证XML合法性,但这不符合你的预期格式。
解决方案
通过手动遍历导入后的节点,移除自动添加的命名空间前缀属性,并恢复子节点原有的命名空间声明,即可得到预期结果。以下是修正后的代码:
$dom = new \DOMDocument(); $dom->preserveWhiteSpace = false; $dom->formatOutput = true; $dom->loadXML("<A></A>"); // 加载要追加的XML片段 $childDom = new \DOMDocument(); $childDom->loadXML("<B><C xmlns='http://foo'></C></B>"); // 导入整个B节点(包含子节点) $childNode = $dom->importNode($childDom->firstChild, true); // 处理自动生成的命名空间前缀 if ($childNode->hasAttribute('xmlns:default')) { $nsUri = $childNode->getAttribute('xmlns:default'); // 移除B节点上冗余的命名空间前缀声明 $childNode->removeAttribute('xmlns:default'); // 遍历所有属于该命名空间的子节点 foreach ($childNode->getElementsByTagNameNS($nsUri, '*') as $node) { // 给子节点添加原有的命名空间声明 if (!$node->hasAttribute('xmlns')) { $node->setAttribute('xmlns', $nsUri); } // 创建不带前缀的新节点,替换原带前缀的节点 $newNode = $dom->createElementNS($nsUri, $node->localName); // 复制原节点的属性 foreach ($node->attributes as $attr) { $newNode->setAttributeNode($dom->importNode($attr, true)); } // 复制原节点的子内容 foreach ($node->childNodes as $child) { $newNode->appendChild($dom->importNode($child, true)); } // 替换节点 $node->parentNode->replaceChild($newNode, $node); } } // 将处理后的节点追加到基础文档 $dom->firstChild->appendChild($childNode); echo $dom->saveXML();
代码说明
- 开启
formatOutput保证输出XML的缩进符合预期,关闭preserveWhiteSpace避免原文档空白干扰格式。 - 导入节点后,检查父节点(B节点)是否存在自动生成的
xmlns:default属性,若存在则获取对应命名空间URI并移除该属性。 - 遍历所有属于该命名空间的子节点,给节点添加原有的
xmlns声明,并创建不带前缀的新节点替换原带前缀的节点,确保结构符合预期。
运行上述代码后,将输出你预期的XML结构:
<A> <B> <C xmlns="http://foo"/> </B> </A>
内容的提问来源于stack exchange,提问作者Ramiro Balado
相关产品推荐
相关产品推荐

