LXML .xpath()方法谓词中上下文节点未被正确识别问题
问题根因说明
该现象是XPath标准的上下文绑定规则导致的,和lxml库版本无关,核心逻辑如下:
- 调用元素对象的
.xpath()方法时,仅整个表达式的最外层初始上下文是当前调用方法的元素(也就是你代码里的tmp,即第一个CONTEXT节点)。 - 表达式中的
//是从文档根节点起始的绝对路径匹配,当遍历到每一个待判断的REF元素时,方括号谓词[]内部的上下文会自动切换为当前正在校验的REF元素,和外层初始上下文不再关联。 - 你写的
//REF[@Id = @Ref]/FIND里,谓词中的@Id和@Ref都是从当前遍历到的REF元素上取属性:但示例XML里所有REF元素都没有定义Ref属性,@Ref的取值永远为空,自然无法和REF自身的Id属性匹配,最终返回空结果。
为什么第二个表达式能返回结果
你写的//REF[@Id = //CONTEXT[@Ref = @Ref]/@Ref]/FIND能匹配到目标节点属于巧合,并没有真正引用初始上下文tmp的属性:
- 内层谓词
[@Ref = @Ref]的上下文是//CONTEXT遍历到的每一个CONTEXT元素,等号两边的@Ref都取自当前遍历到的CONTEXT自身,等价于筛选「存在Ref属性的CONTEXT节点」,再提取这些节点的Ref值用于外层匹配。 - 这个表达式本质是拿所有CONTEXT的Ref值去和REF的Id做匹配,如果你把第二个CONTEXT的Ref属性也改成
Find-3,这个表达式会出现匹配逻辑混乱,并不是你预期的「和选中的第一个CONTEXT的Ref值比对」的效果。
正确实现写法
如果要在谓词里引用调用xpath方法的初始上下文节点的属性,有两种可靠写法:
- 使用lxml支持的
current()函数,显式指代外层初始上下文节点:res_correct = tmp.xpath("//REF[@Id = current()/@Ref]/FIND") - 提前提取目标属性值,作为变量传入XPath表达式,完全规避上下文歧义,兼容性最好:
target_ref_val = tmp.get("Ref") res_correct = tmp.xpath("//REF[@Id = $ref_val]/FIND", ref_val=target_ref_val)
以上两种写法都会准确返回<FIND Solution="1129"/>对应的元素对象。
内容的提问来源于stack exchange,提问作者Görgen
相关产品推荐
相关产品推荐

