xmllint使用contains()的XPath意外匹配不符合条件节点的问题
为什么你的XPath查询意外匹配到了错误节点?
你遇到的这个问题完全是shell命令行的引号解析导致的,和XPath本身的逻辑无关,我来给你拆解清楚:
看你执行的命令:
xmllint --xpath '/prova/parent/groupId/text()[contains(.,'ok')]'
在bash(或类似的Unix shell)中,单引号是不能直接嵌套使用的。shell看到第一个'后,会一直读取字符直到遇到下一个',就认为当前字符串结束了。所以你的命令里,shell会把/prova/parent/groupId/text()[contains(.,当作第一个单引号包裹的内容,ok变成了无引号的独立部分,最后)]是另一个单引号包裹的内容。
最终传递给xmllint的XPath表达式其实是:
/prova/parent/groupId/text()[contains(.,ok)]
这里的ok没有被引号包裹,在XPath中它会被当作节点测试——也就是查找当前上下文节点下名为ok的子节点。但当前上下文是text()节点,文本节点没有子节点,所以ok会返回空序列。而XPath的contains()函数如果第二个参数是空字符串(空序列会被转换为空字符串),会匹配任何非空的文本节点——这就导致你的查询意外匹配到了<groupId>error</groupId>里的文本内容。
修复方案
你有两种简单的方式解决这个引号问题:
- 用双引号包裹整个XPath表达式,内部的单引号保持不变:
这种方式适合你的场景,只要XPath里不包含xmllint --xpath "/prova/parent/groupId/text()[contains(.,'ok')]"$这类shell特殊字符就没问题。 - 在单引号包裹的XPath中,用
'\''转义内部的单引号:
原理是先关闭当前单引号,插入转义的单引号,再重新打开单引号,保证整个XPath能被shell正确传递。xmllint --xpath '/prova/parent/groupId/text()[contains(.,'\''ok'\'')]'
修改后,XPath就能按照你预期的逻辑执行,不会再匹配到error节点了。
内容的提问来源于stack exchange,提问作者tassadar
相关产品推荐
相关产品推荐

