Pourquoi ne fonctionne pas XPath lors du traitement d'un document XHTML avec lxml (en python)?

voix
21

Je teste sur le document de test suivant:

<?xml version=1.0 encoding=UTF-8?>
<!DOCTYPE html PUBLIC -//W3C//DTD XHTML 1.0 Strict//EN 
                      http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd>
<html xmlns=http://www.w3.org/1999/xhtml>
   <head>
        <title>hi there</title>
    </head>
    <body>
        <img class=foo src=bar.png/>
    </body>
</html>

Si je parse le document à l'aide lxml.html, je peux obtenir l'IMG avec un XPath très bien:

>>> root = lxml.html.fromstring(doc)
>>> root.xpath(//img)
[<Element img at 1879e30>]

Cependant, si je parse le document XML et essayer d'obtenir la balise IMG, je reçois un résultat vide:

>>> tree = etree.parse(StringIO(doc))
>>> tree.getroot().xpath(//img)
[]

Je peux accéder à l'élément directement:

>>> tree.getroot().getchildren()[1].getchildren()[0]
<Element {http://www.w3.org/1999/xhtml}img at f56810>

Mais bien sûr, cela ne me aide pas traiter les documents arbitraires. Je voudrais aussi attendre de pouvoir interroger etree pour obtenir une expression XPath qui identifie directement cet élément, qui, techniquement je peux faire:

>>> tree.getpath(tree.getroot().getchildren()[1].getchildren()[0])
'/*/*[2]/*'
>>> tree.getroot().xpath('/*/*[2]/*')
[<Element {http://www.w3.org/1999/xhtml}img at fa1750>]

Mais ce XPath est, encore une fois, de toute évidence pas utile pour l'analyse des documents arbitraires.

Il est évident que je manque une question clé ici, mais je ne sais pas ce qu'elle est. Ma meilleure estimation est qu'il a quelque chose à voir avec les espaces de noms, mais le seul espace de nom défini est la valeur par défaut et je ne sais pas ce que je pourrais avoir besoin d'envisager en ce qui concerne les espaces de noms.

Alors, qu'est-ce que je manque?

Créé 17/11/2008 à 23:42
source utilisateur
Dans d'autres langues...                            


3 réponses

voix
27

Le problème est les espaces de noms. Si on analyse en XML, la balise img est dans le http://www.w3.org/1999/xhtml espace de noms , puisque c'est l'espace de noms par défaut de l'élément. Vous demandez la balise img dans aucun espace de noms.

Essaye ça:

>>> tree.getroot().xpath(
...     "//xhtml:img", 
...     namespaces={'xhtml':'http://www.w3.org/1999/xhtml'}
...     )
[<Element {http://www.w3.org/1999/xhtml}img at 11a29e0>]
Créé 17/11/2008 à 23:45
source utilisateur

voix
7

XPath considère tous les noms préfixés être dans « aucun espace de noms » .

En particulier, la spécification dit:

« Un QName dans le test de nœud est développé en un nom étendu en utilisant les déclarations d'espace de noms à partir du contexte d'expression. C'est la même extension ainsi est fait pour les noms de type d'élément dans début et de fin balises, sauf que l'espace de noms par défaut déclarée avec xmlns est non utilisé: si le QName n'a pas de préfixe, l'espace de nom URI est nul (ce qui est de la même manière les noms d'attributs sont étendus) ".

Voir ces deux explications détaillées du problème et sa solution: ici et ici . La solution consiste à associer un préfixe (avec l'API qui est utilisé) et l'utiliser pour préfixe un nom sans préfixe dans l'expression XPath.

Espérons que cela a aidé.

À votre santé,

Dimitre Novatchev

Créé 18/11/2008 à 00:13
source utilisateur

voix
2

Si vous allez utiliser des balises à partir d'un seul espace de noms seulement, comme je le vois le cas ci-dessus, vous êtes beaucoup mieux à l'aide lxml.objectify.

Dans votre cas, ce serait

from lxml import objectify
root = objectify.parse(url) #also available: fromstring

Vous pouvez accéder aux nœuds comme

root.html
body = root.html.body
for img in body.img: #Assuming all images are within the body tag

Bien qu'il ne soit pas d'une grande aide en html, il peut être très utile en XML bien structuré.

Pour plus d' informations, consultez http://lxml.de/objectify.html

Créé 12/05/2011 à 14:06
source utilisateur

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more