web-dev-qa-db-fra.com

xmllint n'a pas réussi à interroger correctement avec xpath

J'essaie d'interroger un fichier xml généré par adium. xmlwf dit qu'il est bien formé. En utilisant l'option de débogage de xmllint, j'obtiens ce qui suit:

$ 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

Tout semble bien analyser. Cependant, lorsque j'essaie d'interroger même les choses les plus simples, je n'obtiens rien:

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

Que ce passe-t-il? L'exécution de cette même requête exacte à l'aide de xpath renvoie les résultats corrects (mais sans nouvelle ligne entre les résultats). Suis-je en train de faire quelque chose de mal ou est-ce que xmllint ne fonctionne pas correctement?

Voici une version plus courte et anonymisée du xml qui montre le même comportement:

<?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>
46
ailnlv

Je n'utilise pas xmllint, mais je pense que la raison pour laquelle votre XPath ne fonctionne pas est que votre fichier doc.xml utilise un espace de noms par défaut (http://purl.org/net/ulf/ns/0.4-02).

D'après ce que je peux voir, vous avez 2 options.

A. Utilisez xmllint en mode Shell et déclarez l'espace de noms avec un préfixe. Vous pouvez ensuite utiliser ce préfixe dans votre XPath.

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

B. Utilisez local-name() pour faire correspondre les noms des éléments.

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

Vous pouvez également utiliser namespace-uri()='http://purl.org/net/ulf/ns/0.4-02' avec local-name() afin d'être sûr de retourner exactement ce que vous avez l'intention de retourner.

77
Daniel Haley

Je me rends compte que cette question est très ancienne maintenant, mais au cas où cela aiderait quelqu'un ...

J'ai eu le même problème et cela était dû au fait que XML avait un espace de noms (et parfois il était dupliqué à divers endroits dans XML). J'ai trouvé plus simple de supprimer simplement l'espace de noms avant d'utiliser xmllint:

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

Dans mon cas, le XML était UTF-16, j'ai donc dû d'abord convertir en UTF-8 (pour sed):

iconv -f utf16 -t utf8 file.xml | sed -e 's/encoding="UTF-16"?>/encoding="UTF-8"?>/' | sed -e 's/xmlns=".*"//g' | xmllint --xpath "..." -
2
codesniffer