PHP使用DOMDocument遍历DOM元素及子元素替换innerHTML和后续内容
实现思路
- 不能直接修改DOMElement的
nodeValue,该操作会清空元素下所有子节点,仅保留文本内容 - 需要分两部分处理目标内容:
- 元素内部的直接文本节点:仅修改元素下第一层的文本节点,不触碰嵌套的子元素
- 元素闭合后的相邻文本节点:定位到元素的下一个同级节点,若为文本节点则修改
- 采用递归遍历处理所有层级的嵌套元素
- 加载HTML时添加额外参数避免DOMDocument自动补全html/body等默认标签
完整实现代码
<?php $doc = new DOMDocument(); // 屏蔽HTML不规范导致的系统警告 libxml_use_internal_errors(true); // 禁用自动补全HTML根标签、DOCTYPE声明,保持原始结构 $doc->loadHTML( '<div>inHTML1</div>afHTML1<div>inHTML2<div>inHTMLChild2</div>afHTMLChild2</div>afHTML2<div>inHTML3 </div>afHTML3', LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD ); libxml_clear_errors(); // 递归处理节点函数 function processNode(DOMNode $node) { // 仅处理div元素,可按需修改目标标签 if ($node instanceof DOMElement && $node->tagName === 'div') { // 1. 替换div内部的直接文本内容 foreach ($node->childNodes as $child) { if ($child->nodeType === XML_TEXT_NODE) { // 按需修改文本替换规则,示例为加new前缀 $child->nodeValue = 'new ' . trim($child->nodeValue); break; // 仅修改第一个直接文本节点,符合示例需求 } } // 2. 替换div闭合后的后续文本节点 $nextSibling = $node->nextSibling; if ($nextSibling && $nextSibling->nodeType === XML_TEXT_NODE) { // 示例判断:第三个div后的afHTML3不修改,可按需调整规则 if (trim($nextSibling->nodeValue) !== 'afHTML3') { $nextSibling->nodeValue = 'new ' . trim($nextSibling->nodeValue); } } } // 递归处理所有子节点 if ($node->hasChildNodes()) { // 转数组遍历,避免动态DOMNodeList遍历遗漏 foreach (iterator_to_array($node->childNodes) as $child) { processNode($child); } } } // 从根节点开始处理 foreach (iterator_to_array($doc->childNodes) as $rootNode) { processNode($rootNode); } // 输出处理后的HTML $html = $doc->saveHTML(); echo $html; ?>
代码说明
- 加载HTML时的两个参数可以避免DOMDocument自动生成多余的页面结构标签,完全保留原始HTML片段的结构
- 仅针对
XML_TEXT_NODE类型的节点做修改,不会破坏嵌套的子元素结构 - 文本替换规则、目标处理标签都可以根据实际业务需求灵活调整
内容的提问来源于stack exchange,提问作者ThankFull
相关产品推荐
相关产品推荐

