xmllint не может правильно запросить с xpath - PullRequest
46 голосов
/ 25 ноября 2011

Я пытаюсь запросить xml-файл, сгенерированный adium.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>

Ответы [ 2 ]

77 голосов
/ 25 ноября 2011

Я не использую xmllint, но думаю, что ваш XPath не работает, потому что ваш файл doc.xml использует пространство имен по умолчанию (http://purl.org/net/ulf/ns/0.4-02).

Из того, что я вижу, у вас есть 2 варианта.

A. Используйте 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 голос
/ 10 апреля 2019

Я понимаю, что этот вопрос сейчас очень старый, но на случай, если он кому-нибудь поможет ...

Была такая же проблема, и это было связано с тем, что у 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 "..."
...