You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP DOMDocument saveXML如何保留XML原标签闭合格式?

解决DOMDocument无法保留XML原标签闭合样式的问题

首先明确:PHP的DOMDocument没办法直接保留原始XML中空标签的两种闭合样式。因为XML规范里,<tag/>和<tag></tag>语义完全等价,DOM在解析时会把所有空标签统一处理,丢失了原始的语法格式信息,所以saveXML只能二选一输出——要么全自闭合,要么全成对闭合。

要实现保留原样式,得换思路,这里给两个可行方案:

方案一:用XMLReader手动构建输出

XMLReader是基于事件流的解析器,能读取到原始标签的闭合方式(通过isEmptyElement属性判断是不是自闭合标签)。我们可以遍历整个XML文档,逐个节点输出,遇到空标签时根据原始的闭合方式来决定输出格式。

示例代码:

$xml = <<<XML
<example>
    <selfClosed/>
    <empty></empty>
    <text>content</text>
</example>
XML;

$reader = new XMLReader();
$reader->xml($xml);
$output = '';

while ($reader->read()) {
    switch ($reader->nodeType) {
        case XMLReader::ELEMENT:
            $output .= '<' . $reader->name;
            // 处理节点属性
            while ($reader->moveToNextAttribute()) {
                $output .= ' ' . $reader->name . '="' . htmlspecialchars($reader->value) . '"';
            }
            $reader->moveToElement();
            if ($reader->isEmptyElement) {
                $output .= '/>';
            } else {
                $output .= '>';
            }
            break;
        case XMLReader::END_ELEMENT:
            $output .= '</' . $reader->name . '>';
            break;
        case XMLReader::TEXT:
        case XMLReader::CDATA:
            $output .= $reader->value;
            break;
        // 处理注释、处理指令等其他节点类型
        case XMLReader::COMMENT:
            $output .= '<!--' . $reader->value . '-->';
            break;
        case XMLReader::PI:
            $output .= '<?' . $reader->name . ' ' . $reader->value . '?>';
            break;
    }
}

echo $output;

这段代码会完全保留原始的标签闭合样式,输出和输入一致。

方案二:给成对闭合的空标签添加隐形内容

如果不想写复杂的遍历逻辑,可以先预处理原始XML,给那些原本是成对闭合的空标签添加一个零宽空格(&#x200B;)——这个字符不可见,不会影响XML的实际内容,但会让DOMDocument认为该标签不是空元素,保存时就会输出成对闭合的格式;而原本自闭合的标签则保持原样。

示例代码:

$example = <<<XML
<example>
    <selfClosed/>
    <empty></empty>
</example>
XML;

// 预处理:给成对闭合的空标签插入零宽空格
$processedXml = preg_replace('/<(\w+)><\/\1>/', '<$1>&#x200B;</$1>', $example);

$dom = new DOMDocument;
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$dom->loadXML($processedXml);

// 可选:输出后移除零宽空格,完全还原原始格式
$result = str_replace('&#x200B;', '', $dom->saveXML());

echo $result;

需要注意的是,正则表达式的替换逻辑可能需要根据你的XML结构调整,比如标签包含命名空间时,要修改正则匹配规则。

内容的提问来源于stack exchange,提问作者Cristian Belli

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 10:12:42