.xpath中的lxml错误?

问题描述:

通过python的lxml教程中的xpath之后,我发现很难理解2个看起来像是bug的行为。首先,即使我的xpath表达式明确选择了一个元素,lxml似乎也会返回一个列表,其次.xpath似乎返回元素的父元素,而不是由直接xpath搜索表达式选择的元素本身。.xpath中的lxml错误?

我对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 ...>] 

所有p标签应该是doc.findall(".//p")

按照指南,表达nodename选择所有子节点命名节点。 因此,要仅使用节点名(无尾/),必须选择一个命名节点(选择父节点作为命名节点,使用点)。

+0

我的问题不是我无法弄清楚如何使用lxml来选择所有的p标签。我的问题是找出为什么lxml没有错误,因为它的行为与我期望的基于XPath教程 – Trindaz 2012-03-19 03:02:53

这是因为doc的上下文节点是'html'节点。当您使用doc.xpath('body')时,请选择'html'的子元素'body'。这符合XPath 1.0 standard

+0

的行为不同。值得一提的是,'doc.xpath()'总是返回一个列表应该。它简化了使用'.xpath()'的代码。通常总是返回确认相同协议的对象(在这种情况下是一系列元素)是一个好主意。 – jfs 2012-03-19 04:37:46

事实上,doc.xpath("//html[1]")可以返回不止一个节点,并在您的示例中输入不同的文档。该路径选择匹配// html的第一个兄弟。如果有匹配的非同胞元素,它将选择每个元素的第一个兄弟元素。
XPath:(//html)[1]强制执行不同的评估顺序。它选择文档中的所有匹配元素,然后选择第一个。

但是,在任何情况下,总是返回一个列表是一个更好的API设计。否则,在处理列表之前,代码总是必须测试单个值或无值。