
本文介绍如何通过 XPath 表达式 *|text() 同时获取 HTML 元素内的子标签和相邻的纯文本节点,解决“文本不在标签内却需按顺序提取”的常见解析需求。
本文介绍如何通过 xpath 表达式 `*|text()` 同时获取 html 元素内的子标签和相邻的纯文本节点,解决“文本不在标签内却需按顺序提取”的常见解析需求。
在使用 PHP 的 DOMDocument 和 DOMXPath 解析 HTML 时,一个典型难点是:当目标元素(如 )中包含混合内容——即纯文本(text nodes)与嵌套标签(如 、)交错出现时,仅用 *(匹配所有子元素)会忽略那些未被标签包裹的文本内容。
例如,对于如下 HTML 片段:
<p> Example Text 1 <span> Text </span> Example Text 2 @@##@@ </p>
执行 $xpath->evaluate("*", $object) 仅返回 和 两个 DOMElement 节点,而 
"Example Text 1" 和 "Example Text 2"(属于 DOMText 节点)会被完全跳过——因为它们不是元素节点(element),而是文本节点(text node)。
✅ 正确做法是扩展 XPath 表达式,显式包含文本节点:
$subObjects = $xpath->evaluate("*|text()", $object);
该表达式含义为:*匹配当前节点的所有子元素(`)或所有直接子文本节点(text()`)**。注意:
-
text()仅匹配直接子级的文本节点(不递归),符合语义预期; -
*|text()返回的是混合类型的DOMNodeList,其中既含DOMElement,也含DOMText; - 遍历时需判断节点类型以安全提取内容:
foreach ($subObjects as $node) {
if ($node instanceof DOMText) {
echo "Text: '" . trim($node->textContent) . "'\n";
} elseif ($node instanceof DOMElement) {
echo "Tag: tagName . "> (content: '" . trim($node->textContent) . "')\n";
}
}
// 输出顺序与 HTML 中实际排列一致:
// Text: 'Example Text 1'
// Tag: <span> (content: ' Text ')
// Text: 'Example Text 2'
// Tag: @@##@@ (content: '')</span>
⚠️ 注意事项:
-
text()不匹配空白换行符组成的纯空白文本节点(如中的\n ...\n
\n),但textContent默认会保留前后空格;建议用trim()清理; - 若需排除空白文本节点,可改用更精确的 XPath:
*|text()[normalize-space()]; -
DOMXPath::evaluate()返回的DOMNodeList是有序且按文档流排列的,因此无需额外排序即可保证“文本→标签→文本→标签…”的原始结构还原。
总结:*|text() 是处理混合内容(mixed content)的标准 XPath 模式,在 PHP DOM 解析中简洁高效。它让开发者能以统一方式遍历整个子节点序列,真正实现“把文本当节点一样对待”,是构建健壮 HTML 提取逻辑的关键技巧。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











