如何通过lxml扩展函数模仿XPath 2.0函数?

时间:2014-08-08 12:17:49

标签: python xpath lxml

我关注lxml documentation on extension functions并希望模仿XPath 2.0中的upper-case函数。

import urllib
from lxml import html, etree

ns = etree.FunctionNamespace(None)
ns['upper-case'] = lambda context, s: str.upper(s)

google_page = urllib.request.urlopen('http://www.google.com').read().decode('latin-1')
google_page_tree = html.fromstring(google_page)

# text == ['Google.com']
text = google_page_tree.xpath('//a[@id="fehl"]/text()')

# TypeError: descriptor 'upper' requires a 'str' object but received a 'list'
text = google_page_tree.xpath('//a[upper-case(@id)="FEHL"]/text()')    

这似乎不是正确的方法,因为我看到upper-case收到了一个空列表[]。有任何想法吗?谢谢。

2 个答案:

答案 0 :(得分:3)

我不熟悉您的XPath API,但@id在XPath 1.0中选择具有单个属性节点的节点集,在XPath 2.0中选择具有单个属性节点的序列。我假设str.upper方法需要字符串值,而不是//a[upper-case(@id) = ...]尝试//a[upper-case(string(@id)) = ...]。这样,XPath表达式应该产生一个Python函数知道要使用的字符串。

答案 1 :(得分:1)

您不需要模仿 xpath 2.0 功能。您可以通过使用 elementpath 将它们与 lxml 一起使用。

如果你的python是3.6+的话,直接用pip安装

    pip install elementpath

然后,同时导入 elementpath 和 lxml。

    import elementpath
    from lxml import etree
    root = etree.XML("<book name='sense and sensibility'/>")
    elementpath.select(root, "upper-case(@name)")

这将产生:

    'SENSE AND SENSIBILITY'

如果您的 xpath 返回节点,则返回类型是 lxml.etree._Element 列表。因此,您可以将 elementpath 视为 lxml 的扩展。

参考:

elementpath docs

XQuery 1.0 and XPath 2.0 Functions and Operators (Second Edition)

What's New in XPath 2.0