如何用DOMDocument移除标签保留内容并清理Word导出的HTML
解决方案
核心目标:把Word生成的冗余HTML转换成仅含无属性<div>标签和有效文本的结构,彻底清除所有冗余标签(如<script>、<o:p>、<span>、<h1>、<p>)及所有元素属性。
问题根源
原代码的核心问题:
- 用
getElementsByTagName('*')遍历的是动态节点列表,修改节点(删除/替换)会导致列表结构乱序,出现漏处理或属性莫名恢复的情况。 - 没处理
<h1>、<p>这类需要转成<div>的标签,也没清除<o:p>这种Word专属的冗余标签。 - 最终输出带
<body>标签,不符合预期格式。
修正后的代码
$dom = new DOMDocument; // 加载HTML,避免自动补全默认的html/body标签 $dom->loadHTML($filecontent, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); $xpath = new DOMXPath($dom); // 1. 先删掉所有没用的标签:script、o:p $uselessTags = ['script', 'o:p']; foreach ($uselessTags as $tag) { $nodes = $xpath->query("//{$tag}"); foreach ($nodes as $node) { $node->parentNode->removeChild($node); } } // 2. 清除span标签,保留里面的文本内容 $spanNodes = $xpath->query("//span"); foreach ($spanNodes as $span) { // 把span的子节点(文本/其他内容)移到span的父节点里,放在span前面 while ($span->firstChild) { $span->parentNode->insertBefore($span->firstChild, $span); } // 删掉空的span标签 $span->parentNode->removeChild($span); } // 3. 把h1、p等块级标签转成无属性div,同时清掉所有元素属性 $blockTags = ['h1', 'p', 'div']; foreach ($blockTags as $tag) { $nodes = $xpath->query("//{$tag}"); // 倒序遍历,避免动态节点列表的索引混乱问题 for ($i = $nodes->length - 1; $i >= 0; $i--) { $node = $nodes->item($i); // 清掉所有属性 while ($node->hasAttributes()) { $node->removeAttribute($node->attributes->item(0)->name); } // 不是div的话,替换成div标签 if ($node->tagName !== 'div') { $div = $dom->createElement('div'); // 把原节点的所有内容移到新div里 while ($node->firstChild) { $div->appendChild($node->firstChild); } // 用div替换原节点 $node->parentNode->replaceChild($div, $node); } } } // 4. 输出所有无属性div的内容 $divNodes = $xpath->query("//div"); foreach ($divNodes as $div) { echo $dom->saveHTML($div) . "\n"; }
代码说明
- 先清无用标签:彻底移除
<script>、<o:p>这类没有有效内容的标签,避免干扰后续处理。 - 处理span标签:通过移动子节点再删除span的方式,保留文本内容同时清除冗余标签。
- 倒序遍历节点:解决动态节点列表的索引混乱问题,确保每个节点都能被正确处理。
- 标签转换+属性清除:把非div的块级标签替换成无属性div,同时清空所有元素的冗余属性。
- 纯div输出:直接遍历所有div节点并输出,彻底去掉
<body>等多余外层标签。
内容的提问来源于stack exchange,提问作者Chimdi
相关产品推荐
相关产品推荐

