2012-03-19 2 views
0

После прохождения xpath в учебнике lxml для python мне сложно понять 2 поведения, которые кажутся мне ошибками. Во-первых, lxml, похоже, возвращает список, даже когда мое выражение xpath явно выбирает только один элемент, а во-вторых. Xpath, кажется, возвращает родительские элементы, а не сами элементы, выбранные прямым поиском поиска xpath.ошибка lxml в .xpath?

Является ли мое понимание XPath все неправильным или у lxml действительно есть ошибка?

Скрипт для репликации поведение Я говорю:

from lxml.html.soupparser import fromstring 
doc = fromstring(""" 
    <html> 
     <head></head> 
     <body> 
      <p>Paragraph 1</p> 
      <p>Paragraph 2</p> 
     </body> 
    </html> 
""") 

print doc.xpath("//html") 
#[<Element html at 1f385e0>] 
#(This makes sense - return a list of all possible matches for html) 

print doc.xpath("//html[1]") 
#[<Element html at 1f385e0>] 
#(This doesn't make sense - why do I get a list when there 
#can clearly only be 1 element returned?) 

print doc.xpath("body") 
#[<Element body at 1d003e8>] 
#(This doesn't make sense - according to 
#http://www.w3schools.com/xpath/xpath_syntax.asp if I use a tag name 
#without any leading/I should get the *child* nodes of the named 
#node, which in this case would mean I get a list of 
#p tags [<Element p at ...>, <Element p at ...>] 

ответ

0

Все р-теги должны быть doc.findall(".//p")

В соответствии с руководством, выражение nodenameВыбирает все дочерние узлы названного узла. Таким образом, чтобы использовать только nodename (без трейлинга /), вы должны выбрать именованный узел (чтобы выбрать родительский узел как именованный узел, используйте точку).

+0

Моя проблема не в том, что я не могу понять, как использовать lxml, чтобы выбрать все теги p. Моя проблема заключается в том, почему именно lxml не имеет ошибки, потому что он ведет себя по-другому, что я ожидаю, основываясь на учебнике XPath. – Trindaz

3

Это потому, что контекстный узел doc - это 'html' узел. Когда вы используете doc.xpath('body'), выберите дочерний элемент 'body' из 'html'. Соответствует XPath 1.0 standard

+0

. Возможно, стоит упомянуть, что 'doc.xpath()' всегда возвращает список, как он должен. Это упрощает код, который использует '.xpath()'. В общем случае хорошей идеей всегда является возврат объектов, подтверждающих один и тот же протокол (в этом случае последовательность элементов). – jfs

0

Фактически, doc.xpath("//html[1]") может возвращать более одного узла с другим входным документом из вашего примера. Этот путь выбирает первого брата, который соответствует // html. Если есть совпадающие элементы без брака, он будет выбирать первого брата каждого из них.
XPath: (//html)[1] заставляет другой порядок оценки. Он выбирает все соответствующие элементы в документе, а затем выбирает первый.

Но, в любом случае, это лучший дизайн API, который всегда возвращает список. В противном случае перед обработкой списка код всегда должен проверять значения одиночного или ни одного.

Смежные вопросы