xmllint无法使用xpath正确查询

时间:2011-11-25 01:57:39

标签: 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

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

$ xmllint --xpath '/chat' doc.xml 
XPath set is empty

发生了什么事?使用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>

3 个答案:

答案 0 :(得分:77)

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

从我所看到的,你有两个选择。

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

    xmllint --shell doc.xml
    / > setns x=http://purl.org/net/ulf/ns/0.4-02
    / > xpath /x:chat

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

    xmllint --xpath /*[local-name()='chat']

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

答案 1 :(得分:1)

我知道这个问题现在已经很老了,但是如果它可以帮助某人...

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

sed -e 's/xmlns=".*"//g' file.xml | xmllint --xpath "..."

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

iconv -f utf16 -t utf8 file.xml | sed -e 's/xmlns=".*"//g' | xmllint --xpath "..."

答案 2 :(得分:0)

如果您被允许在您的环境中安装 powershell(它也可用于 Linux),您可以这样做:

Select-Xml -XPath '/ns:chat' -Namespace $Namespace .\doc.xml | foreach { $_.Node }
   xmlns   : http://purl.org/net/ulf/ns/0.4-02
   account : foo@bar.com
   service : MSN
   event   : event
   message : message

当然,xpath 的所有规则都适用于此。访问节点的文本内容:

Select-Xml -XPath '/ns:chat/ns:message' -Namespace $Namespace .\doc.xml |foreach {$_.Node.InnerXML }
<div xmlns="http://purl.org/net/ulf/ns/0.4-02"><span style="color: #000000; font-family: Helvetica; font-size: 12pt;">hi</span></div>

或者sender属性的内容:

Select-Xml -XPath '/ns:chat/ns:message/@sender' -Namespace $Namespace .\doc.xml |foreach {$_.Node }

#text
-----
foo@bar.com