XPath是否明确允许未定义变量?xmlstarlet无报错疑问
命令行引号问题的根源
你最初的命令xmlstarlet sel -t -v '//div[contains(@class,'addresses')]/a'之所以结果超预期,是因为shell的引号解析规则:外层用单引号包裹整个XPath参数时,内部的'addresses'会被shell当成外层单引号的闭合标记,导致实际传给xmlstarlet的XPath变成了//div[contains(@class,addresses)]/a——这里的addresses不再是字符串常量,而是被当作一个变量。
解决方法很简单:要么把内部的字符串改成双引号包裹,比如'//div[contains(@class,"addresses")]/a';要么对内部的单引号做转义,比如'//div[contains(@class,\'addresses\')]/a',这样shell就会把整个XPath当作一个完整参数传递。
contains(@class,addresses)不报错的原因
这是XPath 1.0的语法特性:未定义的变量会被解析为空字符串,而不是抛出错误。
所以contains(@class, addresses)实际等价于contains(@class, '')——而XPath中,任何非空字符串都包含空字符串,因此这个条件会匹配所有带有class属性且属性值不为空的<div>节点,这就是你拿到远超预期结果的原因。
XPath 1.0本身并不要求对未定义变量报错,属于合法语法,因此xmlstarlet不会触发错误或警告。
xmlstarlet是否有警告标志?
目前xmlstarlet的sel命令没有专门针对未定义变量的警告开关。它依赖的libxml2 XPath解析器(默认用XPath 1.0)本身也不会对未定义变量发出警告,而xmlstarlet的源码里也没有实现这类警告逻辑。
如果需要严格检查XPath中的变量问题,可以考虑使用支持XPath 2.0及以上版本的工具,这类版本的XPath会对未定义变量明确抛出错误。
内容的提问来源于stack exchange,提问作者android.weasel

