Xmllint не может правильно запросить с помощью xpath
Я пытаюсь запросить файл xml, созданный adium. xmlwf говорит, что он хорошо сформирован. Используя опцию xmllint debug, я получаю следующее:
$ 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
[email protected]
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="[email protected]" service="MSN">
<event type="windowOpened" sender="[email protected]" time="2011-11-22T00:34:43-03:00"></event>
<message sender="[email protected]" 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>
Ответы
Ответ 1
Я не использую 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()
, чтобы вы точно вернули то, что собираетесь направить.
Ответ 2
Я понимаю, что этот вопрос сейчас очень старый, но на тот случай, если он кому-то поможет...
Была такая же проблема, и это было связано с тем, что у 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/encoding="UTF-16"?>/encoding="UTF-8"?>/' | sed -e 's/xmlns=".*"//g' | xmllint --xpath "..." -