python之lxml快速上手_Element(一)
来源:互联网 发布:淘宝大学电商总裁班 编辑:程序博客网 时间:2024/06/12 01:41
The Element class
对于使用任何一种编程语言的开发人员来说,xml的处理总是不可避免,甚至是非常常见的。而lxml则是在python语言中,功能最丰富、最易于使用,同时性能也相当不错的xml、html处理库。虽然网上也有许多介绍lxml用法的文章,但是,学习任意一个第三方库(框架、新技术),官方文档无疑是不可多得的第一手好材料。于是,为了让其他有需要的同学也能快速上手,针对手册中The lxml.etree Tutorial部分,进行了部分翻译。同时,本人英语水平有限,或者理解上有偏差,望不吝指正。
Element在ElementTree API中是主要的容器对象。大部分XML tree函数都是通过它访问的。要创建它也是很简单,只需使用Element工厂函数:
>>> root = etree.Element("root")
xml节点的标签名可通过tag属性访问:
>>> print(root.tag)root
Elements在xml中通过树状结构组织的。如果需要创建子节点,并把它们追加到一个父节点,你可以使用append()方法:
>>> root.append( etree.Element("child1") )
然而,(创建子节点)的需求是如此普遍,有一个更加简短、高效的方式:使用SubElement工厂函数。跟Element一样,它接受同样的参数,但是需额外的一个父节点参数作为它的第一个参数:
>>> child2 = etree.SubElement(root, "child2")>>> child3 = etree.SubElement(root, "child3")
为了更加直观地了解到刚才创建的就是xml,你可以使用序列化:
>>> print(etree.tostring(root, pretty_print=True))<root> <child1/> <child2/> <child3/></root>
Elements are lists
为了更加简单、直接地访问(上面所创建的)子节点,elements尽可能地模仿常规python List的行为:
>>> child = root[0]>>> print(child.tag)child1>>> print(len(root))3>>> root.index(root[1]) # lxml.etree only!1>>> children = list(root)>>> for child in root:... print(child.tag)child1child2child3>>> root.insert(0, etree.Element("child0"))>>> start = root[:1]>>> end = root[-1:]>>> print(start[0].tag)child0>>> print(end[0].tag)child3
在ElementTree 1.3 and lxml 2.0之前,你可以检查一个Element的真假值,来判定它是否有孩子节点。如果孩子节点组成的list是空的:
if root: # 在后续版本中将不再起作用 print("The root element has children")
上面的条件测试将不再起作用。因此,许多用户可能会惊奇地发现,任意一个节点像上面一样进行条件测试,结果都是False。作为替代的做法,使用len(element)语意上更加明确, 也意味着更少的错误倾向。
>>> print(etree.iselement(root)) # 测试root是否是某种类型的ElementTrue>>> if len(root): # 测试root是否有孩子节点... print("The root element has children")The root element has children
还有一个需要说明的情况,lxml中Elements的行为 (在2.0及之后的版本中)与常规python List、原始的ElementTree会有偏差。
>>> for child in root:... print(child.tag)child0child1child2child3>>> root[0] = root[-1] # this moves the element in lxml.etree!>>> for child in root:... print(child.tag)child3child1child2
在上面的例子中,最后一个节点被移动到不同的位置(第一个),而不是被拷贝到另一个位置。当它被移至另一个不同的位置,它从它原有的位置被移除。在一般的list中,对象可以在同一时间点出现在不同位置,而像上面的情况,在list中仅会拷贝最后一个节点的引用到第一个位置,因此list中包含两个同样的对象:
>>> l = [0, 1, 2, 3]>>> l[0] = l[-1]>>> l[3, 1, 2, 3]
注意,在原始的ElementTree中,一个Element对象可以位于任意xml树对象的任意一个位置,它允许像list一样执行同样的拷贝操作。很明显的一个缺点,对节点的任意改变都将应用到所有它在tree中出现的地方。而这却不一定是你想要的。
上面这种特殊的处理方式,有一个好处就是:在lxml.etree中的任意一个Element都有唯一一个父节点,可通过getparent()获取,而在原始ElementTree中是不支持的。
>>> root is root[0].getparent() # lxml.etree only!True
如果你想在lxml.etree中拷贝一个节点到另外一个位置,可以考虑使用独立的标准库模块copy的deepcopy():
>>> from copy import deepcopy>>> element = etree.Element("neu")>>> element.append( deepcopy(root[1]) )>>> print(element[0].tag)child1>>> print([ c.tag for c in root ])['child3', 'child1', 'child2']
如果你想访问一个节点的兄弟节点,可以:
>>> root[0] is root[1].getprevious() # lxml.etree only!True>>> root[1] is root[0].getnext() # lxml.etree only!True
Elements carry attributes as a dict
XML节点支持属性,你可以直接在Element工厂函数中构建它们:
>>> root = etree.Element("root", interesting="totally")>>> etree.tostring(root)b'<root interesting="totally"/>'
属性仅仅是无序的键值(key-value)对,因此,处理它们的一个简便方式就是通过Elements的类字典接口:
>>> print(root.get("interesting"))totally>>> print(root.get("hello"))None>>> root.set("hello", "Huhu")>>> print(root.get("hello"))Huhu>>> etree.tostring(root)b'<root interesting="totally" hello="Huhu"/>'>>> sorted(root.keys())['hello', 'interesting']>>> for name, value in sorted(root.items()):... print('%s = %r' % (name, value))hello = 'Huhu'interesting = 'totally'
有时,你只是想做item的查找,或者因为一些其他的原因,想要获得“真实”的类字典对象,并把它传递给周边,你可以使用attrib属性:
>>> attributes = root.attrib>>> print(attributes["interesting"])totally>>> print(attributes.get("no-such-attribute"))None>>> attributes["hello"] = "Guten Tag">>> print(attributes["hello"])Guten Tag>>> print(root.get("hello"))Guten Tag
注意,attrib是一个由Element本身支持的类字典对象。这也意味者对Element所做的改动会反射到attrib上,同样,XML tree将一直保持“激活”状态,只要它的任意节点的attrib还在使用中。为了获取一个独立的,不依赖于XML tree的attrib快照,可以把它拷贝到一个字典:
>>> d = dict(root.attrib)>>> sorted(d.items())[('hello', 'Guten Tag'), ('interesting', 'totally')]
Elements contain text
Elements可以包含文本:
>>> root = etree.Element("root")>>> root.text = "TEXT">>> print(root.text)TEXT>>> etree.tostring(root)b'<root>TEXT</root>'
对于许多xml文档(以数据为主),这是唯一能找到文本的地方。(文本)通常被tree底部的叶子节点包裹者。
然而,如果xml被用作标签文本例如HTML,文本也可以出现在不同的节点之间:
<html><body>Hello<br/>World</body></html>
在这里,
标签被文本包围。这在document-style、mixed-content类型的xml中经常被提及。 Elements使用通过tail属性来支持这一点的。它包含紧跟该节点的文本,直到XML tree中的下一个节点:
>>> html = etree.Element("html")>>> body = etree.SubElement(html, "body")>>> body.text = "TEXT">>> etree.tostring(html)b'<html><body>TEXT</body></html>'>>> br = etree.SubElement(body, "br")>>> etree.tostring(html)b'<html><body>TEXT<br/></body></html>'>>> br.tail = "TAIL">>> etree.tostring(html)b'<html><body>TEXT<br/>TAIL</body></html>'
这两个属性.text、.tail已经足够呈现XML文档中的任意文本。
然而,当你序列化一个Element时,你并总是希望tail text出现在结果中。为了达成这个目的,tostring()函数接受一个关键字参数with_tail:
>>> etree.tostring(br)b'<br/>TAIL'>>> etree.tostring(br, with_tail=False) # lxml.etree only!b'<br/>'
如果你仅仅需要文本text,不需要中间的节点,你必须以正确的顺序,递归连接所有的text、tail text属性。再一次,tostring()方法大显身手,这一次使用method关键字参数:
>>> etree.tostring(html, method="text")b'TEXTTAIL'
- python之lxml快速上手_Element(一)
- python之lxml快速上手_Element(二)
- python之lxml快速上手_ElementTree(三)
- Python快速上手(一)
- Python快速上手(二)
- Python快速上手(三)
- Django 快速上手(一)
- Mongodb一之快速上手部署
- Python之lxml
- Python之lxml
- python爬虫之lxml
- python模块系列(一)之文档解析利器lxml
- Python 编程快速上手
- python request快速上手
- python request快速上手
- Python requests快速上手
- python编程快速上手
- SVN快速上手(一)安装
- GCD与并发编程
- Java面试题全集(上)
- 微服务--分布式事务的实现方法及替代方案
- 安卓退出应用的安全方式
- 进程间通信--管道、消息队列
- python之lxml快速上手_Element(一)
- com.alibaba.fastjson.JSONObject的使用
- 安卓AS打包报错org.gradle.process.internal.ExecException
- Java面试题全集(中)
- 浅析智能指针
- day56_电力项目_POI导出JXL导入
- Socket编程
- Java面试题全集(下)
- Qt仿win7自动顶部最大化左侧右侧半屏效果