PHP实现HTML拆分为单词并保留指定<span>元素的技术问询
解决方案:保留特定
<span>并拆分HTML为单词 咱们来一步步搞定这三个问题,完美实现你想要的HTML文本处理效果:
问题2:仅捕获带itemtype的<span>元素,排除其内部文本节点
当前的XPath同时选中了目标<span>和它内部的文本节点,导致重复输出了"Bob Ferris"。咱们只需要调整XPath表达式,排除那些父节点是带itemtype属性的<span>的文本节点:
原XPath:
.//span[@itemtype]|.//text()[normalize-space()]
修改后的XPath:
.//span[@itemtype]|.//text()[normalize-space() and not(parent::span[@itemtype])]
这个表达式的逻辑很明确:选择所有带itemtype的<span>,再选择所有非空文本节点,但刻意排除掉属于目标<span>内部的文本,这样就不会出现重复内容了。
问题1:将文本节点拆分为单个单词并去除标点
XPath是用来选择节点的工具,没法直接把文本节点拆分成单个单词。咱们可以在PHP里对文本节点的内容做字符串处理,用正则表达式来拆分并清理标点:
使用preg_split(),匹配任意非单词字符(\W+)来拆分,同时去掉空值:
$words = preg_split('/\W+/', trim($node->nodeValue), -1, PREG_SPLIT_NO_EMPTY);
这个正则会把文本按空格、逗号、句号等非单词字符拆分,trim()先去掉首尾空白,PREG_SPLIT_NO_EMPTY确保不会生成空的单词项,完美得到干净的单词列表。
问题3:支持访问<span>元素的属性
只要咱们选中的是<span>元素节点(nodeType=1),直接用$node->getAttribute()就能访问它的任意属性,比如$node->getAttribute('itemtype')或者$node->getAttribute('itemscope'),完全没有障碍。
完整实现代码
把以上三点整合起来,完整的可运行代码如下:
$html = '<html><body> <h1>My header</h1> <p>A test <b>paragraph</b> with <span itemscope itemtype="http://schema.org/Person">Bob Ferris</span> a person.</p> </body></html>'; $dom = new DOMDocument(); // 禁用HTML结构不规范时的错误提示 libxml_use_internal_errors(true); $dom->loadHTML($html); libxml_clear_errors(); $xpath = new DOMXpath($dom); // 使用修改后的XPath表达式 $nodes = $xpath->query('.//span[@itemtype]|.//text()[normalize-space() and not(parent::span[@itemtype])]'); foreach($nodes as $node) { if ($node->nodeType === XML_ELEMENT_NODE) { // 处理<span>元素 echo "元素节点:" . $node->nodeValue . "<br>"; // 访问属性示例 echo " itemtype属性:" . $node->getAttribute('itemtype') . "<br>"; } elseif ($node->nodeType === XML_TEXT_NODE) { // 处理文本节点,拆分为单词 $words = preg_split('/\W+/', trim($node->nodeValue), -1, PREG_SPLIT_NO_EMPTY); foreach ($words as $word) { echo "单词:" . $word . "<br>"; } } }
输出结果:
单词:My 单词:header 单词:A 单词:test 单词:paragraph 单词:with 元素节点:Bob Ferris itemtype属性:http://schema.org/Person 单词:a 单词:person
内容的提问来源于stack exchange,提问作者Phil Gyford
相关产品推荐
相关产品推荐

