XPath提取含<br>标签文本异常:合并多行文本到单个数组项
解决带
<br>标签的引用文本提取与作者配对问题 我明白你现在卡在哪了——当遇到带<br>的引用内容时,你的XPath直接抓取所有文本节点,导致每一行都变成了单独的数组项,和后面的作者完全对应不上。咱们换个思路,先抓每个完整的引用容器,再在容器里分别提取合并后的文本和对应的作者,就能解决这个问题。
问题根源
你原来用的//*[contains(@class, normalize-space('$quote'))]//text()会选中目标元素下所有独立的文本节点,<br>标签会把文本拆成多个节点,所以每个换行都成了数组里的单独项。而每个引用容器只有一个作者,这样数组里的文本项数量会远多于作者,自然配对失败。
修复方案
先选中每个完整的引用容器(也就是<div class="b-list-quote2__item">),然后在每个容器内分别提取合并后的引用文本和对应作者:
// 先抓取所有引用容器,确保每个容器对应一个作者 $quoteContainers = $finder->query("//div[contains(@class, 'b-list-quote2__item')]"); $dataArr = []; foreach ($quoteContainers as $container) { // 1. 提取合并后的引用文本:直接用节点的textContent会自动合并所有子文本 $quoteNode = $container->query(".//a[contains(@class, 'b-list-quote2__item-text')]")->item(0); $quoteText = $quoteNode ? trim($quoteNode->textContent) : ''; // 2. 提取对应作者,并处理名字格式 $authorNode = $container->query(".//div[contains(@class, 'b-list-quote2__item-category')]/a")->item(0); $authorName = ''; if ($authorNode) { $authorParts = preg_split("/[\s,-,@]+/", $authorNode->textContent); // 处理名字分段,同时加空值保护避免索引错误 switch (true) { case count($authorParts) < 5: $authorName = $authorParts[1] ?? ''; break; case count($authorParts) > 6: $authorName = implode(' ', array_slice($authorParts, 1, 4)); break; case count($authorParts) > 5: $authorName = implode(' ', array_slice($authorParts, 1, 3)); break; default: $authorName = implode(' ', array_slice($authorParts, 1, 2)); break; } } // 添加到结果数组 $dataArr[] = $quoteText; $dataArr[] = $authorName; }
关键改进点
- 以容器为单位遍历:每个
<div class="b-list-quote2__item">对应一组“引用+作者”,从根源上保证数量匹配。 - 自动合并文本:使用节点的
textContent属性,它会自动把该节点下所有子文本节点(包括<br>前后的内容)拼接成一个完整字符串,不需要手动遍历子节点。 - 增加空值保护:在访问数组索引时用
?? ''避免因作者名字格式异常导致的报错。
测试效果
对于你提供的有<br>的HTML结构,这段代码会生成你期望的数组:
[0] => Quote line 0, Quote line 1, Quote line 2, Quote line 3, [1] => Tesla
内容的提问来源于stack exchange,提问作者Ricardo
相关产品推荐
相关产品推荐

