如何使用XPath匹配HTML编码文本?解决 匹配失效问题
问题原因
HTML中的 在被DOMDocument解析后,会转换为Unicode不间断空格字符(U+00A0),你的原有代码仅匹配普通半角空格(U+0020)包裹的目标字符串,自然无法识别被 包裹的场景。
修复方案
有两种常用实现方式,可根据需求选择:
方案1:XPath层面统一替换空白字符再匹配
直接在XPath表达式中把所有空白字符(包含不间断空格、制表符、换行符等)统一替换为普通空格,再进行包含匹配,代码修改如下:
$d->loadHTML('<?xml encoding="UTF-8">'.$html); $xpath = new DOMXPath($d); $txt = "rest"; $txt_lower = strtolower($txt); // 构造XPath表达式:先转小写,再归一化空白,前后拼接空格实现全单词匹配 $xpath_expr = '/html/body//text()[ contains( concat(" ", normalize-space(translate(., "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz")), " "), " '.$txt_lower.' " ) and not(ancestor::a) and not(ancestor::h2) and not(ancestor::h3) ]'; $nodes = $xpath->query($xpath_expr);
这里用到的normalize-space()函数会自动把所有类型的空白统一替换为单个普通空格,同时去掉首尾空白,手动在前后拼接空格就可以实现全单词精确匹配,不会出现部分匹配的问题。
方案2:PHP层面预处理HTML源码
如果不想修改原有XPath逻辑,也可以在加载HTML之前直接把源码里的所有 替换成普通空格:
// 替换所有 为普通空格 $html = str_replace(' ', ' ', $html); $d->loadHTML('<?xml encoding="UTF-8">'.$html); // 后续保持原有代码逻辑不变即可 $xpath = new DOMXPath($d); $txt="rest"; $txt=' '.$txt.' '; $txt1=strtolower($txt); $xpath->query('/html/body//text()['. 'contains('. 'translate(.,"'.strtoupper($txt).'","'.$txt1.'"),'. '"'.$txt1.'"'. ']'.'[not(ancestor::a)][not(ancestor::h2)][not(ancestor::h3)]');
这种方案改造成本更低,适合不想调整原有XPath逻辑的场景。
内容的提问来源于stack exchange,提问作者saurabh yadav
相关产品推荐
相关产品推荐

