xmllint执行合法XPath3查询返回‘XPath set is empty’问题排查
xmllint执行XPath查询返回空集合的原因及解决办法
现有h3.html文件内容如下:
$ cat h3.html <body> <h3 class="heading"><span class="content">First Title</span></h3> <h3 class="no-num no-ref heading settled"><span class="level">45.6</span></h3> <h3 class="no-num no-ref heading settled" id="informative"><span class="content">Informative References</span><a class="self-link" href="#informative"></a></h3> <h3 class="heading"><span class="content">More Stuff</span></h3> </body> $
使用xmllint执行XPath查询//h3//span[@class="content"]/text()时,无论是否使用--shell、--html参数,均返回“XPath set is empty”:
$ xmllint --shell --xpath "//h3//span[@class="content"]/text()" h3.html XPath set is empty / > ^C $ xmllint --xpath "//h3//span[@class="content"]/text()" h3.html XPath set is empty $ xmllint --html --xpath "//h3//span[@class="content"]/text()" h3.html XPath set is empty $
所用xmllint为Ubuntu 22.04上的libxml2 20913版本,编译包含XPath特性。但用hq工具执行相同查询可得到预期结果:
$ cat h3.html | hq '//h3//span[@class="content"]/text()' First Title Informative References More Stuff $
原因
问题出在shell的引号解析上:你用双引号包裹整个XPath表达式,而表达式内部的@class="content"又用了双引号,shell会把内层双引号当成表达式的结束标记,导致实际传给xmllint的XPath被截断为//h3//span[@class=content]/text()——这里的content没有被引号包裹,xmllint会把它当作节点名称而非字符串,自然匹配不到任何结果。
解决办法
有两种可行的修正方式:
- 用单引号包裹整个XPath表达式,这样内层的双引号不会被shell解析:
xmllint --html --xpath '//h3//span[@class="content"]/text()' h3.html - 转义内层的双引号,在双引号前加反斜杠
\,告诉shell这是字符串的一部分:xmllint --html --xpath "//h3//span[@class=\"content\"]/text()" h3.html
执行上述修正后的命令,就能得到预期的结果:
First Title Informative References More Stuff
内容的提问来源于stack exchange,提问作者user3313834
相关产品推荐
相关产品推荐

