我关注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
收到了一个空列表[]
。有任何想法吗?谢谢。
答案 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
的扩展。
参考:
XQuery 1.0 and XPath 2.0 Functions and Operators (Second Edition)