XPath的谓词是写在方括号中的表达式,用于对节点集进行筛选,只保留满足表达式条件的节点,是XPath实现精准节点定位的核心语法。谓词可以基于节点的位置、属性、文本内容、子节点状态等多个维度设置过滤条件,让开发者从大量节点中快速提取目标内容。

XPath谓词的基础概念
谓词的本质是一个返回布尔值的判断条件,XPath会对当前选中的节点集逐个应用谓词条件,只有条件为真的节点会被保留到结果集中。谓词始终紧跟在节点选择表达式之后,用方括号[]包裹,一个XPath表达式中可以包含多个连续的谓词,多个条件会依次生效,相当于逻辑与的关系。
比如基础表达式//book会选中文档中所有的book节点,加上谓词//book[price>30]之后,就只会选中price子节点值大于30的book节点。
常用谓词过滤节点的场景
1. 基于位置的谓词过滤
位置谓词是最常用的过滤方式之一,用于选中指定位置的节点,位置索引从1开始计数,不是从0开始。
[1]:选中当前节点集中的第一个节点[last()]:选中当前节点集中的最后一个节点[last()-1]:选中当前节点集中的倒数第二个节点[position()<3]:选中当前节点集中位置小于3的节点,也就是前两个节点
以下是基于位置过滤的XPath示例,假设我们要从一组图书节点中选中第一本和第三本图书:
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book>
<title>XML基础教程</title>
<price>25</price>
</book>
<book>
<title>XPath实战指南</title>
<price>35</price>
</book>
<book>
<title>Python数据解析</title>
<price>40</price>
</book>
</bookstore>
对应的XPath表达式和结果如下:
//book[1] // 选中第一本book,title为XML基础教程 //book[position()=3] // 选中第三本book,title为Python数据解析
2. 基于属性的谓词过滤
通过节点的属性值过滤节点是非常常见的需求,使用@属性名可以获取节点的属性值,再结合比较运算符设置条件。
比如我们要选中所有分类为技术的book节点,对应XML结构如下:
<bookstore>
<book category="technology">
<title>XPath实战指南</title>
</book>
<book category="literature">
<title>散文精选</title>
</book>
</bookstore>
对应的XPath表达式为:
//book[@category="technology"] // 选中category属性为technology的book节点
如果要选中属性值包含特定字符串的节点,可以结合contains()函数使用:
//book[contains(@category,"tech")] // 选中category属性包含tech字符串的book节点
3. 基于文本内容的谓词过滤
如果需要筛选文本内容符合特定条件的节点,可以使用text()获取节点的文本内容,再设置判断条件。
比如要选中title文本为XPath实战指南的book节点,表达式为:
//book[title/text()="XPath实战指南"]
如果要选中title文本包含实战关键词的节点,结合contains()函数:
//book[contains(title/text(),"实战")]
4. 基于子节点状态的谓词过滤
谓词中还可以判断子节点的存在性或者子节点的属性、文本状态,实现更复杂的过滤逻辑。
比如要选中包含price子节点且price值大于30的book节点:
//book[price and price>30]
要选中没有category属性的book节点:
//book[not(@category)]
多谓词组合使用
一个XPath表达式中可以添加多个谓词,多个谓词会按顺序依次过滤节点,最终得到同时满足所有条件的节点集。
比如要选中分类为技术、价格大于30、且是前两本的book节点:
//book[@category="technology"][price>30][position()<3]
上述表达式会先过滤出category为技术的book,再从结果中过滤出price大于30的book,最后只保留前两个符合要求的节点。
谓词使用注意事项
- 谓词中的比较运算符需要正确转义,比如大于号要写成
>,小于号写成<,避免被解析为HTML标签。 - 位置索引从1开始,不要使用0作为位置条件,否则不会匹配到任何节点。
- 如果谓词中需要判断节点是否存在,直接使用节点名即可,比如
[price]表示存在price子节点,不需要写成[price!=null]。 - 多个条件如果是或的关系,可以使用
or运算符,比如//book[@category="tech" or price>40],表示选中分类为tech或者价格大于40的book节点。