在XML或HTML文档解析场景中,我们常常需要筛选出父节点是某个特定元素的节点,XPath提供了多种语法可以实现这个需求,下面详细介绍具体的实现方法。

方法一:使用parent轴定位
parent轴是XPath中用于获取当前节点父节点的轴类型,我们可以通过parent轴判断父节点是否符合特定条件,从而筛选出目标节点。
语法格式为:子节点名称[parent::特定父节点名称],其中parent::表示获取当前节点的父节点,后面的特定父节点名称就是我们要匹配的父节点标签名。
假设我们有如下XML文档结构:
<root>
<group class="valid">
<item>苹果</item>
<item>香蕉</item>
</group>
<group class="invalid">
<item>橘子</item>
</group>
<single>
<item>葡萄</item>
</single>
</root>
如果我们想要选择父节点是group元素的所有item节点,可以使用如下XPath表达式:
//item[parent::group]
这个表达式会匹配到苹果、香蕉、橘子这三个item节点,而不会匹配到父节点是single的葡萄节点。
方法二:使用谓词直接判断父节点属性
如果我们需要根据父节点的属性来筛选,还可以在谓词中直接访问父节点的属性进行判断,这种方式比parent轴更灵活,支持属性匹配。
比如上面的XML文档中,我们想要选择父节点group的class属性为valid的所有item节点,可以使用如下表达式:
//item[parent::group/@class='valid']
这个表达式会匹配到苹果和香蕉两个节点,排除掉父节点class为invalid的橘子节点。
方法三:结合层级路径直接定位
如果文档结构比较固定,我们也可以通过直接指定父节点的路径来筛选子节点,这种方式的可读性更强,适合结构明确的场景。
比如要获取group节点下的所有item节点,可以直接写:
//group/item
这个表达式会直接匹配所有父节点是group的item节点,效果和//item[parent::group]一致,但是写法更简洁。
不同方法的适用场景
- 如果只需要判断父节点的标签名,使用
parent::父节点名或者层级路径父节点名/子节点名都可以,后者更简洁。 - 如果需要判断父节点的属性或者更复杂的父节点条件,优先使用parent轴结合谓词判断的方式,灵活性更高。
- 如果文档结构层级较深,使用层级路径的时候要注意路径的准确性,避免匹配到非预期的节点。
代码示例(Python解析HTML场景)
下面用Python的lxml库演示如何使用XPath筛选父节点为特定元素的节点,假设我们要解析一段HTML内容:
from lxml import etree
# 待解析的HTML内容
html_content = """
<div class="container">
<ul class="list">
<li>列表项1</li>
<li>列表项2</li>
</ul>
<div class="other">
<li>其他项1</li>
</div>
</div>
"""
# 解析HTML
html = etree.HTML(html_content)
# 选择父节点是ul的所有li节点
target_li = html.xpath('//li[parent::ul]/text()')
print("父节点是ul的li内容:", target_li)
# 等价于使用层级路径的方式
target_li2 = html.xpath('//ul/li/text()')
print("层级路径方式获取的结果:", target_li2)
运行上述代码,输出结果如下:
父节点是ul的li内容: ['列表项1', '列表项2'] 层级路径方式获取的结果: ['列表项1', '列表项2']
可以看到两种方式都能正确筛选出父节点是ul的li节点,不会匹配到父节点是div的其他项1。
注意事项
使用parent轴的时候要注意,parent轴只会返回当前节点的直接父节点,不会返回祖先节点,如果需要判断更上层的祖先节点,可以使用ancestor轴。
另外,XPath表达式中的标签名要和文档中的标签名完全一致,包括大小写,因为XML和HTML的标签名是大小写敏感的(HTML在解析时部分场景不敏感,但建议保持和文档一致)。