
本文介绍如何通过 XPath 表达式 *|text() 同时获取 HTML 元素内的子标签和相邻的纯文本节点,解决“文本不在标签内却需按顺序提取”的常见解析需求。
本文介绍如何通过 xpath 表达式 `*|text()` 同时获取 html 元素内的子标签和相邻的纯文本节点,解决“文本不在标签内却需按顺序提取”的常见解析需求。
在使用 PHP 的 DOMDocument 和 DOMXPath 解析 HTML 时,一个典型难点是:当目标元素(如 <p></p>)中包含混合内容——即纯文本(text nodes)与嵌套标签(如 <span></span>、<img alt="如何使用 PHP DomXPath 提取标签内独立的纯文本节点" >)交错出现时,仅用 *(匹配所有子元素)会忽略那些未被标签包裹的文本内容。
例如,对于如下 HTML 片段:
<p> Example Text 1 <span> Text </span> Example Text 2 <img src="example.png" alt="如何使用 PHP DomXPath 提取标签内独立的纯文本节点" > </p>
执行 $xpath->evaluate("*", $object) 仅返回 <span></span> 和 <img alt="如何使用 PHP DomXPath 提取标签内独立的纯文本节点" > 两个 DOMElement 节点,而 "Example Text 1" 和 "Example Text 2"(属于 DOMText 节点)会被完全跳过——因为它们不是元素节点(element),而是文本节点(text node)。
✅ 正确做法是扩展 XPath 表达式,显式包含文本节点:
立即学习“PHP免费学习笔记(深入)”;
$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: <" . $node->tagName . "> (content: '" . trim($node->textContent) . "')\n";
}
}
// 输出顺序与 HTML 中实际排列一致:
// Text: 'Example Text 1'
// Tag: <span> (content: ' Text ')
// Text: 'Example Text 2'
// Tag: <img alt="如何使用 PHP DomXPath 提取标签内独立的纯文本节点" > (content: '')⚠️ 注意事项:
-
text()不匹配空白换行符组成的纯空白文本节点(如<p>\n <span>...</span>\n</p>中的\n),但textContent默认会保留前后空格;建议用trim()清理; - 若需排除空白文本节点,可改用更精确的 XPath:
*|text()[normalize-space()]; -
DOMXPath::evaluate()返回的DOMNodeList是有序且按文档流排列的,因此无需额外排序即可保证“文本→标签→文本→标签…”的原始结构还原。
总结:*|text() 是处理混合内容(mixed content)的标准 XPath 模式,在 PHP DOM 解析中简洁高效。它让开发者能以统一方式遍历整个子节点序列,真正实现“把文本当节点一样对待”,是构建健壮 HTML 提取逻辑的关键技巧。



















