官网地址: https://lxml.de/xpathxslt.html
导入:
from lxml import etree
lxml.tree 支持 ElementTree 和 Element 上的 find,findall,findtext 方法的简单路径语法, 作为特定的 lxml 扩展, 这些类提供了 xpath()方法, 该方法支持完整 xpath 语法中的表达式, 以及定制的扩展函数.
xpath()方法
对于 ElementTree,xpath 方法对文档 (绝对路径) 或者根节点执行全局(相对路径) xpath 查询
- def demo_1():
- f = StringIO('<foo><bar></bar></foo>')
- tree = etree.parse(f)
- r = tree.xpath('/foo/bar')
- print(len(r))
- print(r[0].tag)
- r_2 = tree.xpath('bar')
- print(r_2[0].tag)
在 Element 上使用 xpath() 时, xpath()表达式根据元素 (相对路径) 或根树 (绝对路径) 查询:
- def demo_2():
- f = StringIO('<foo><bar></bar></foo>')
- tree = etree.parse(f)
- root = tree.getroot()
- r = root.xpath('bar')
- print(r[0].tag)
- bar = root[0]
- r = bar.xpath('/foo/bar')
- print(r[0].tag)
xpath()方法支持 xpath 变量:
- def demo_3():
- f = StringIO('<foo><bar></bar></foo>')
- tree = etree.parse(f)
- root = tree.getroot()
- expr = "//*[local-name() = $name]"
- print(root.xpath(expr, name='foo')[0].tag)
- print(root.xpath(expr, name="bar")[0].tag)
- print(root.xpath("$text", text="Hello World!"))
命名空间和前缀
如果 XPath 表达式使用名称空间前缀, 则必须在前缀映射中定义它们. 为此, 将一个字典传递给 namespace 关键字参数, 该参数将 XPath 表达式中使用的名称空间前缀映射到名称空间 uri
- def demo_4():
- f = StringIO('''<a:foo xmlns:a="http://codespeak.net/ns/test1" xmlns:b="http://codespeak.net/ns/test2">
- <b:bar>Text</b:bar>
- </a:foo>
- ''')
- doc = etree.parse(f)
- r = doc.xpath('/x:foo/b:bar',
- namespaces={'x': 'http://codespeak.net/ns/test1',
- 'b': 'http://codespeak.net/ns/test2'})
- print(len(r))
- print(r[0].tag)
- print(r[0].text)
在这里选择的前缀并没有连接到 xml 文档中使用的前缀, 文档可以定义任何前缀, 包括空前缀, 也不会破坏上面的代码
注意 XPath 没有默认的命名空间, 因此, XPath 中没有定义空前缀, 不能在命名空间前缀映射中使用
XPath 返回值
XPath 返回值的类型取决于使用的 Xpath 表达式:
(1) True 或者 False
- (2) float
- (3) "智能的"string
XPath 字符串的结果是 "智能的", 因为它们提供了一个 getparent()方法, 该方法知道它们的起源:
(i)对于属性值, result.getparent()返回携带它们的元素. 例如 //foo/@attribute, 它的父元素是一个 foo 元素.
(ii)对于 text()函数(如 //text()), 它返回包含返回的文本或尾部的元素.
以使用布尔属性 is_text,is_tail 和 is_attribute 来区分不同的文本源.
注意, getparent()不一定总是返回一个元素. 例如, XPath 函数 string()和 concat()将构造没有原点的字符串. 对于它们, getparent()将不返回任何值.
有些情况下 smart string 并不受欢迎. 例如: 它意味着树将字符串保持活动状态, 如果字符串值是树中唯一真正需要的东西, 那么它可能会对内存产生相当大的影响. 对于这些情况, 可以使用关键字 smart_strings 禁用父关系
- def demo_5():
- root = etree.xml("<root><a>TEXT</a></root>")
- find_text = etree.XPath("//text()")
- text = find_text(root)[0]
- print(text)
- print(text.getparent().text)
- # 禁用父关系
- find_text = etree.XPath("//text()", smart_strings=False)
- text = find_text(root)[0]
- print(text)
- hasattr(text, 'getparent')
(4) list 或者 items
生成 XPath 表达式
ElementTree 对象有一个 getpath(element)方法, 它返回一个结构的, 绝对的 XPath 表达式来查找该元素:
- def demo_6():
- a = etree.Element("a")
- b = etree.SubElement(a, "b")
- c = etree.SubElement(a, "c")
- d1 = etree.SubElement(c, "d")
- d2 = etree.SubElement(c, "d")
- tree = etree.ElementTree(c)
- print(tree.getpath(d2)) # /c/d[2]
- print(tree.xpath(tree.getpath(d2)) == [d2])
XPath 类
XPath 类将 XPath 表达式编译为可调用函数
- def demo_7():
- root = etree.xml("<root><a><b/></a><b/></root>")
- find = etree.XPath("//b")
- print(find(root)[0].tag)
编译花费的时间和 xpath()方法相同, 但是每个类实例化编译一次, 这能提高重复计算相同 Xpath 表达式的效率. 就像 xpath()方法一样, XPpath 类支持 xpath 变量
- def demo_8():
- root = etree.xml("<root><a><b/></a><b/></root>")
- count_elements = etree.XPath("count(//*[local-name() = $name])")
- print(count_elements(root, name="a"))
- print(count_elements(root, name="b"))
这支持非常有效地计算 XPath 表达式的修改版本, 因为编译仍然只需要一次.
前缀到命名空间的映射可以作为第二个参数传递:
- def demo_9():
- root = etree.xml("<root xmlns='NS'><a><b/></a><b/></root>")
- find = etree.XPath("//n:b", namespaces={'n': 'NS'})
- print(find(root)[0].tag)
XPath 中的正则表达式
默认情况下, XPath 支持 EXSLT 名称空间中的正则表达式, 也可以使用 regexp 关键字禁用它, 默认值是 True
- def demo_10():
- regexpNS = "http://exslt.org/regular-expressions"
- find = etree.XPath("//*[re:test(.,'^abc$','i')]", namespaces = {'re': regexpNS})
- root = etree.xml("<root><a>aB</a><b>aBc</b></root>")
- print(find(root)[0].text)
后面还有一些看不下去了, 下一篇写下 xpath 的常规用法, 点击下载代码
来源: http://www.bubuko.com/infodetail-2933993.html