2008-11-17 15 views
21

jestem testowania przeciwko następującym dokumencie testowym:Dlaczego xpath nie działa podczas przetwarzania dokumentu XHTML za pomocą lxml (w python)?

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

Gdybym analizowania dokumentu przy użyciu lxml.html mogę uzyskać IMG z XPath dobrze:

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

Jednak gdybym analizować dokumentu w formacie XML i postarać się znacznika IMG, dostaję pusty wynik:

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

mogę poruszać się do elementu bezpośrednio:

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

Ale oczywiście to nie pomaga mi w przetwarzaniu dowolnych dokumentów. Chciałbym również oczekiwać, aby być w stanie kwerendy etree uzyskać wyrażenie XPath, które będą bezpośrednio zidentyfikować ten element, który technicznie mogę zrobić:

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

Ale XPath jest, ponownie, oczywiście nie przydatna do analizowania dowolnych dokumentów .

Oczywiście brakuje tu kluczowej kwestii, ale nie wiem, co to jest. Domyślam się, że ma to coś wspólnego z przestrzeniami nazw, ale jedyny zdefiniowany obszar nazw jest domyślny i nie wiem, co jeszcze muszę wziąć pod uwagę w odniesieniu do przestrzeni nazw.

Więc, czego mi brakuje?

Odpowiedz

27

Problem stanowią przestrzenie nazw. Gdy parsowany jest jako XML, znacznik img znajduje się w przestrzeni nazw http://www.w3.org/1999/xhtml, ponieważ jest to domyślny obszar nazw dla elementu. Pytasz o znacznik img bez przestrzeni nazw.

Spróbuj tego:

>>> tree.getroot().xpath(
...  "//xhtml:img", 
...  namespaces={'xhtml':'http://www.w3.org/1999/xhtml'} 
... ) 
[<Element {http://www.w3.org/1999/xhtml}img at 11a29e0>] 
+0

Cytując http://codespeak.net/lxml/xpathxslt.html << Opcjonalnie można podać argument nazw słów kluczowych, które powinny być słownikiem odwzorowywania prefiksów przestrzeni nazw używanych w wyrażeniu XPath do nazw URI przestrzeni nazw >> –

+0

Jeśli chcesz wyszukiwać za pomocą zwartych wyrażeń Xpath w domyślnej przestrzeni nazw elementu głównego, możesz użyć sztuczki działającej dla xhtml lub innych schematów, takich jak: 'nsmap = {'h': tree.getroot(). nsmap [Brak]}; elem.xpath ('// h: img', namespaces = nsmap' - ułatwia pisanie zapytania w sposób kompaktowy. – mkj

7

XPath considers all unprefixed names to be in "no namespace".

W szczególności spec mówi:

„To QName w teście węzła rozpręża się do rozszerzonej-name za pomocą deklaracji przestrzeni nazw z kontekstu wypowiedzi Jest to ta sama droga ekspansja odbywa się za nazwami typu element. znaczniki start i end z wyjątkiem tego, że domyślna przestrzeń nazw zadeklarowana przy użyciu xmlns nie jest używana: jeśli nazwa QName nie ma prefiksu, to identyfikator URI przestrzeni nazw jest pusty (w ten sam sposób rozszerzane są nazwy atrybutów). "

Zobacz te dwa szczegółowe wyjaśnienia problemu i jego rozwiązania: here i here. Rozwiązaniem jest skojarzenie prefiksu (z używanym interfejsem API) i użycie go do przedrostowania dowolnej nieprefiksowanej nazwy w wyrażeniu XPath.

Mam nadzieję, że to pomogło.

Cheers,

Dimitre Novatchev

2

Jeśli masz zamiar używać znaczników z tylko jednej przestrzeni nazw, jak widzę to w przypadku powyżej, są znacznie lepiej wyłączyć za pomocą lxml.objectify.

W twoim przypadku to będzie jak

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

Można uzyskać dostęp do węzłów jako

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

Chociaż nie może być bardzo pomocne w HTML, to może być bardzo przydatna w dobrze zorganizowany xml.

Aby uzyskać więcej informacji, sprawdź http://lxml.de/objectify.html

Powiązane problemy