xmllint无法使用xpath正确查询

ail*_*nlv 49 xml xpath xmllint

我正在尝试查询adium生成的xml文件.xmlwf说它形成得很好.通过使用xmllint的调试选项,我得到以下内容:

$ xmllint --debug doc.xml
DOCUMENT
version=1.0
encoding=UTF-8
URL=doc.xml
standalone=true
  ELEMENT chat
    default namespace href=http://purl.org/net/ulf/ns/0.4-02
    ATTRIBUTE account
      TEXT
        content=foo@bar.com
    ATTRIBUTE service
      TEXT compact
        content=MSN
    TEXT compact
      content= 
    ELEMENT event
      ATTRIBUTE type
Run Code Online (Sandbox Code Playgroud)

一切似乎都解析得很好.但是,当我尝试查询最简单的东西时,我什么都得不到:

$ xmllint --xpath '/chat' doc.xml 
XPath set is empty
Run Code Online (Sandbox Code Playgroud)

发生了什么?使用xpath运行完全相同的查询会返回正确的结果(但结果之间没有换行符).我做错了什么还是xmllint不能正常工作?

这是一个较短的,匿名的xml版本,它显示了相同的行为:

<?xml version="1.0" encoding="UTF-8" ?>
<chat xmlns="http://purl.org/net/ulf/ns/0.4-02" account="foo@bar.com" service="MSN">
<event type="windowOpened" sender="foo@bar.com" time="2011-11-22T00:34:43-03:00"></event>
<message sender="foo@bar.com" time="2011-11-22T00:34:43-03:00" alias="foo"><div><span style="color: #000000; font-family: Helvetica; font-size: 12pt;">hi</span></div></message>
</chat>
Run Code Online (Sandbox Code Playgroud)

Dan*_*ley 81

我不使用xmllint,但我认为你的XPath不起作用的原因是你的doc.xml文件使用的是默认的命名空间(http://purl.org/net/ulf/ns/0.4-02).

从我所看到的,你有2个选择.

A.在shell模式下使用xmllint并使用前缀声明命名空间.然后,您可以在XPath中使用该前缀.

    xmllint --shell doc.xml
    / > setns x=http://purl.org/net/ulf/ns/0.4-02
    / > xpath /x:chat
Run Code Online (Sandbox Code Playgroud)

B.使用local-name()匹配的元素名称.

    xmllint --xpath /*[local-name()='chat']
Run Code Online (Sandbox Code Playgroud)

您可能还想namespace-uri()='http://purl.org/net/ulf/ns/0.4-02'与之一起使用,local-name()因此您肯定会准确地返回您想要返回的内容.

  • **C.**`cat foo.xml | sed'2 s/xmlns =".*"// g'| xmllint --xpath ...` (11认同)
  • 注意示例A.和B.如果您没有访问根路径将失败,在这种情况下您需要双斜杠,例如xmllint --xpath"//*[local-name()='chat']" .请参阅http://stackoverflow.com/questions/27311314/how-to-get-the-tag-yweathercondition-from-yahoo-weather-rss-with-xmllint?noredirect=1#comment43085213_27311314 (6认同)
  • 嘿,这是对读者的评论,其用例略有不同,而不是批评你的答案,准确回答问题.有命名空间问题的人可能是新手,因此我认为值得指出. (6认同)
  • NB.这可能会很快变得混乱和冗长.[本文](http://blog.powered-up-games.com/wordpress/archives/70)有一个关于这个主题的好教程; 例如,必须将`namespace-uri()`添加到需要它的路径的每个部分. (4认同)
  • @ Avt'W观察对我们新手很有帮助.@ daniel-haley感谢shell提示.这就是我认为全线的样子.`xmllint --xpath"//*[local-name()='chat'和namespace-uri()='http://purl.org/net/ulf/ns/0.4-02']"` (2认同)
  • 我想知道为什么他们使shell选项`setr​​ootns`从根节点声明注册所有命名空间,但不在CLI模式下注册:( (2认同)
  • 不是用sed解析XML是世界上最好的想法,但正则表达式可能太贪婪了.要删除名称空间声明而不超出您的意思,请使用`sed'/ xmlns ="[^"]*"// g'`. (2认同)

cod*_*fer 9

我意识到这个问题现在已经很老了,但万一它对某人有帮助......

有同样的问题,这是由于 XML 具有命名空间(有时它在 XML 的不同位置重复)。发现在使用 xmllint 之前删除命名空间最简单:

sed -e 's/xmlns="[^"]*"//g' file.xml | xmllint --xpath "..." -
Run Code Online (Sandbox Code Playgroud)

在我的情况下,XML 是 UTF-16,所以我必须先转换为 UTF-8(对于 sed):

iconv -f utf16 -t utf8 file.xml | sed -e 's/encoding="UTF-16"?>/encoding="UTF-8"?>/' | sed -e 's/xmlns="[^"]*"//g' | xmllint --xpath "..." -
Run Code Online (Sandbox Code Playgroud)