为什么 XPath 查询需要重复指定 a 元素?
数据阿明
结论
这几个表达式筛选和提取的节点不同。div[a="Download"] 根据子元素 a 的内容筛选 div,后面的 /a/@href 则从符合条件的 div 中提取子元素 a 的 href 属性。筛选条件中的 a 和结果路径中的 a 用途不同。
三种写法的区别
原查询:
//div[@id="button_block"]/div[a="Download"]/a/@href
其中:
div[a="Download"]选择包含子元素a,且该a的字符串值为Download的div。/a/@href先选择这个div的子元素a,再取它的href属性。
也就是说,条件检查子元素 a,返回的也是这个子元素 a 上的属性。
改成 div["Download"] 后,"Download" 是非空字符串。在 XPath 谓词中,它会转换为布尔值 true,所以该谓词不会根据元素文本筛选 div,而会匹配前面路径中符合条件的所有 div。之后 /a/@href 会提取这些 div 下的 a 链接,因此可能返回多个结果。
改成 div[a="Download"]/@href 后,筛选条件仍检查子元素 a 的内容,但末尾的 @href 指向当前选中的 div。如果页面上的 href 在子元素 a 上,而不在 div 上,这个表达式就无法选到目标属性。
可用写法
要保留原查询的筛选和提取逻辑,可以直接使用原表达式:
//div[@id="button_block"]/div[a="Download"]/a/@href
也可以把文本条件放到要提取的 a 元素上:
//div[@id="button_block"]/div/a[.="Download"]/@href
第二种写法会直接选择字符串值为 Download 的 a 元素,再提取它的 href。它是否与原查询完全等价,取决于页面结构。如果一个 div 中可能有多个 a,或者还需要其他筛选条件,就应保留相应的父级约束。
注意
这里的 = 比较的是 XPath 节点的字符串值,而不是 HTML 属性名本身。如果 a 中包含嵌套元素,它的字符串值也会包含后代文本。若要匹配精确文本,还需考虑空白字符和页面的实际结构。
备注:内容仅供参考。
