PHP:如何用DOMDocument和DOMXPath遍历所有HTML节点(含被其他节点分割的文本节点)并修改内容,同时避免自动添加html/body标签
问题解答
1. 获取类似"TEST_1"、"TEST_2"的文本节点
你说得没错,TEST_1和TEST_2属于直接附着在非叶子元素上的文本节点(它们的父节点h3包含其他子元素<b>),而你的原XPath只选中了无子元素的元素节点,所以没覆盖到这些文本节点。
要选中这类文本节点,你可以用XPath表达式定位非空白且父元素包含其他子元素的文本节点,代码示例如下:
$dom = new DOMDocument(); $dom->loadHTML(' <h3> TEST_1 <b>b tag content</b> TEST_2 </h3> <p>p tag content </p> '); $xpath = new DOMXPath($dom); // 原逻辑:修改无子元素的元素节点内容 foreach ($xpath->evaluate('//*[count(*) = 0]') as $node) { $node->nodeValue = "Changed " . $node->nodeValue; } // 新增逻辑:修改父元素有子元素的非空白文本节点 foreach ($xpath->evaluate('//text()[normalize-space(.) != "" and parent::*[count(*) > 0]]') as $textNode) { $textNode->nodeValue = "Changed " . $textNode->nodeValue; } echo $dom->saveHTML();
运行这段代码后,TEST_1和TEST_2会被修改为Changed TEST_1和Changed TEST_2,最终输出的内容会符合你的预期。
2. 阻止saveHTML自动添加<html>和<body>标签
DOMDocument的loadHTML方法默认会补全HTML文档结构,导致输出时自动添加DOCTYPE、<html>和<body>标签。解决这个问题有两种常用方式:
方式一:指定输出<body>节点的内容
通过saveHTML()的参数,仅输出<body>标签内部的内容:
// 你的DOM修改逻辑... echo $dom->saveHTML($dom->getElementsByTagName('body')->item(0));
这样输出的结果会去掉外层的<html>和DOCTYPE,只保留<body>内的元素。
方式二:使用LIBXML的选项禁用自动补全
在loadHTML时传入LIBXML_HTML_NODEFDTD(禁用DOCTYPE)和LIBXML_HTML_NOIMPLIED(禁用自动添加html/body标签)选项,需要PHP 5.4+支持:
$dom = new DOMDocument(); // 加载HTML时禁用自动补全结构 $dom->loadHTML(' <h3> TEST_1 <b>b tag content</b> TEST_2 </h3> <p>p tag content </p> ', LIBXML_HTML_NODEFDTD | LIBXML_HTML_NOIMPLIED); $xpath = new DOMXPath($dom); // 你的修改逻辑... echo $dom->saveHTML();
这种方式下,输出的内容就是你原始输入的结构,不会添加额外的标签。
内容的提问来源于stack exchange,提问作者Denis Petrov
相关产品推荐
相关产品推荐

