【译】:lxml.etree官方文档
本文翻译自:http://lxml.de/tutorial.html, 作者:Stefan Behnel
这是一个关于使用lxml.etree进行XML处理的教程。它简要介绍了ElementTree API的主要概念,以及一些简单的增强功能,使你的编程更容易。
有关API的完整参考,请参考生成的API文档。
内容:
• 元素类
· 元素是列表
· 元素以属性为特征
· 元素包含文本
· 使用XPath查找文本
· 树迭代
· 序列化
• ElementTree类
• 从字符串和文件解析
· fromstring()函数
· XML()函数
· parse()函数
· 解析器对象
· 增量解析
· 事件驱动解析
• Namespaces
• The E-factory
• ElementPath
导入lxml.etree的常见方法如下:
from lxml import etree
如果你的代码仅使用ElementTree API,并不依赖于特定的lxml.etree的任何功能,你还可以利用下面的导入方法:
try:
from lxml import etree
print("running with lxml.etree")
except ImportError:
try:
#Python 2.5
import xml.etree.cElementTree as etree
print("running with cElementTree on Python 2.5+")
except ImportError:
try:
#Python 2.5
import xml.etree.ElementTree as etree
print("running with ElementTree on Python 2.5+")
except ImportError:
try:
#正常的cElementTree安装
import cElementTree as etree
print("running with cElementTree")
except ImportError:
try:
#正常的ElementTree安装
import elementtree.ElementTree as etree
print("running with ElementTree")
except ImportError:
print("Failed to import ElementTree from any known place")
为了编写可移植代码,本教程在例子中说明了API的哪一部分是由Fredrik Lundh的ElementTree库定义的原始ElementTree API的lxml.etree的扩展。
» 元素类
单个元素是ElementTree API的主要的容器对象。大多数XML树功能都是通过这个类访问的。元素可以通过Element factory轻松创建:
>>> root = etree.Element("root")
元素的XML标签名通过tag属性访问:
>>> print (root.tag) root
元素以XML树结构组织。要添加子元素并将其添加到父元素中,可以使用append()方法:
>>> root.append( etree.Element("child1") )
然而,这是很常见的。有一个更短更有效的方法做到这一点:SubElement factory。它接受与Element factory相同的参数,但要求父元素作为第一个参数:
>>> child2 = etree.SubElement(root, "child2") >>> child3 = etree.SubElement(root, "child3")
要看到真正的XML,你可以序列化创建的树:
>>> print (etree.tostring(root, pretty_print = True))
<root>
<child1/>
<child2/>
<child3/>
</root>
元素是列表
为了更容易、更直接的访问这些子元素,元素尽可能地模仿python列表的行为:
>>> child = root[0]
>>> print (child.tag)
child1
>>> print (len(root))
3
>>> root.index(root[1])
1
>>> children = list(root)
>>> for child in root:
... print (child.tag)
child1
child2
child3
>>> 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和lxml 2.0之前,你还可以检查一个元素的真值,看它是否有子代,即如果子列表为空:
if root:
print ("The root element has children")
这不再受支持,因为人们倾向于期待"something“被评估为True,期待元素成为"something”,它们可能有子代吗?所以很多用户惊奇的发现任何元素都会在上面的if语句中被评估为False。相反的,使用len(element)更明确,更少出错。
>>> print (etree.iselement(root)) #测试它是否是element类型
True
>>> if len(root): #测试它是否有子代
... print ("The root element has children")
The root element has children
还有一种重要的情况,其中lxml(2.0及以上版本)中Elements的行为偏离了列表和原始的ElementTree(1.3之前的版本或Python2.7/3.2):
>>> for child in root: ... print (child.tag) child0 child1 child2 child3 >>> root[0] = root[-1] >>> for child in root: ... print (child.tag) child3 child1 child2
在这个例子中,最后一个元素被剪切到一个不同的位置,而不是复制,即当它被放在不同的位置时,它被自动从它前一个位置移除。在列表中,对象可以同时出现在多个位置,上述分配只会将item引用复制到第一个位置,以便两者都包含相同的item。
>>> 1 = [0, 1, 2, 3] >>> 1[0] = 1[-1] >>> 1 [3, 1, 2, 3]
注意在原始的ElementTree中,单个的Element对象可以位于任意数量的树中的任意数量位置,这允许与列表相同的复制操作,明显的缺点是对这种元素的修改将会适用于它出现树中的所有地方,这可能是也可能不是初衷。
这个区别的优点是,lxml.etree中的Element总是具有一个父对象,可以通过getparent()方法进行查询。这在原始的ElementTree中是不支持的。
>>> root is root[0].getparent() True
如果要将单个元素复制到lxml.etree中的不同位置,请考虑使用Python标准库中的复制模块来创建一个独立的深层副本:
>>> 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() True >>> root[1] is root[0].getnext() True
元素以属性为特征
XML元素支持属性。你可以在Element factory直接创建它们:
>>> root = etree.Element("root", interesting = "totally")
>>> etree.tostring(root)
b'<root interesting = "totally"/>'
属性只是无序的name-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 insteresting = "totally" hello = "Huhu"/>'
>>> sorted(root.keys())
['hello', 'insteresting']
>>> for name, value in sorted(root.items()):
... print ('%s = %r' % (name, value))
hello = 'Huhu'
interesting = 'totally'
对于你想查找item或其他原因来获取一个'real'类似字典对象的情况,例如传递给它,你可以使用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本身支持的类似dict的对象。这意味着对元素的任何修改都反映在属性中,反之亦然。这也意味着,只要一个元素的attrib在使用,XML树就活跃在内存中。要获取不依赖XML树的属性的独立快照,将其复制到dict中:
>>> d = dict(root.attrib)
>>> sorted(d.items())
[('hello', 'Guten Tag'), ('insteresting', 'totally')]
元素包含文本
元素可以包含文本:
>>> root = etree.Element("root")
>>> root.text = "TEXT"
>>> print (root.text)
TEXT
>>> etree.tostring(root)
b'<root>TEXT</root>'
在许多XML文档(以数据为中心的文档)中,这是唯一可以找到文本的地方。它由叶子标签封装在树层次结构的底部。
然而,如果XML用于标记的文本文档,例如(X)HTML,文本也可以出现在不同元素之间,就在树的中间:
<html><body>Hello</br>World</body></html>
这里,</br>标签由文本环绕。这通常被称为文本样式或混合内容XML。元素通过尾部属性来支持它。它包含直接跟随元素的文本,直到XML树中的下一个元素:
>>> 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类之外,ElementTree API不需要任何特殊的文本节点,它往往会得到一些方法(正如你从传统的的DOM API中知道的那样)。
然而,有些情况下尾部文本也会妨碍。例如,当你从树中序列化一个元素时,你并不总是希望在结果中显示尾部文本(尽管你仍然希望其子代码的尾部文本)。为此,tostring()函数接受关键字参数with_tail:
>>> etree.tostring(br) b'<br/>TAIL' >>> etree.tostring(br, with_tail=False) # lxml.etree only! b'<br/>'
如果你想读的只有文字,即没有任何中间变量,你必须递归串联所有文字和以正确的顺序属性。再次使用tostring()函数来救援,这次使用method关键字:
>>> etree.tostring(html, method="text") b'TEXTTAIL'
【译】:lxml.etree官方文档的更多相关文章
- 【译】Spark官方文档——编程指南
本文翻自官方博客,略有添加:https://github.com/mesos/spark/wiki/Spark-Programming-Guide Spark发指南 从高的面看,其实每一个Spark的 ...
- 【译】Spark官方文档——Spark Configuration(Spark配置)
注重版权,尊重他人劳动 转帖注明原文地址:http://www.cnblogs.com/vincent-hv/p/3316502.html Spark主要提供三种位置配置系统: 环境变量:用来启动 ...
- 别开心太早,Python 官方文档的翻译差远了
近几天,很多公众号发布了 Python 官方文档的消息.然而,一个特别奇怪的现象就发生了,让人啼笑皆非. Python 文档的中文翻译工作一直是“默默无闻”,几个月前,我还吐槽过这件事<再聊聊P ...
- SolrJ API 官方文档最佳实践
以下内容译自Solr Wiki官方文档,版权没有,随意转载. Solrj 是一个访问solr的Java客户端.它提供了一个java接口用于添加更新和查询solr索引.本页面介绍SolrJ最新版本1.4 ...
- HBase 官方文档
HBase 官方文档 Copyright © 2010 Apache Software Foundation, 盛大游戏-数据仓库团队-颜开(译) Revision History Revision ...
- 读BeautifulSoup官方文档之与bs有关的对象和属性(1)
自从10号又是5天没更, 是, 我再一次断更... 原因是朋友在搞python, 老问我问题, 我python也是很久没碰了, 于是为了解决他的问题, 我只能重新开始研究python, 为了快速找回感 ...
- HBase 官方文档0.90.4
HBase 官方文档0.90.4 Copyright © 2010 Apache Software Foundation, 盛大游戏-数据仓库团队-颜开(译) Revision History Rev ...
- [E] Shiro 官方文档阅读笔记 The Reading Notes of Shiro's Offical Docs
官方文档: https://shiro.apache.org/reference.html https://shiro.apache.org/java-authentication-guide.htm ...
- Akka Typed 官方文档之随手记
️ 引言 近两年,一直在折腾用FP与OO共存的编程语言Scala,采取以函数式编程为主的方式,结合TDD和BDD的手段,采用Domain Driven Design的方法学,去构造DDDD应用(Dom ...
随机推荐
- Qt Creator 如何支持并行?
PRO 文件中加入以下语句即可 #OpenMP QMAKE_CXXFLAGS += -openmp QMAKE_LFLAGS += -openmp
- 洛谷 P4071 [SDOI2016]排列计数
洛谷 这是一道组合数学题. 对于一个长为n的序列,首先我们要选m个使之稳定\(C^{m}_{n}\). 且要保证剩下的序列不稳定,即错排\(D_{n-m}\). 所以答案就是:\[ANS=C^{m}_ ...
- PAT 1068. 万绿丛中一点红(20)
对于计算机而言,颜色不过是像素点对应的一个24位的数值.现给定一幅分辨率为MxN的画,要求你找出万绿丛中的一点红,即有独一无二颜色的那个像素点,并且该点的颜色与其周围8个相邻像素的颜色差充分大. 输入 ...
- 20170421 F110 常见问题
F110常見問題以及處理方式 1. Vendor中沒有與F110中相同的Payment method 解決辦法: 在Vendor主檔中維護Payment method 2. 結報被Block 解決辦法 ...
- eval in Shell
语法:eval cmdLine eval会对后面的cmdLine进行两遍扫描,如果第一遍扫描后,cmdLine是个普通命令,则执行此命令: 如果cmdLine中含有变量的间接引用,则保证间接引用的语义 ...
- Hibernate学习---关联关系映射
关联关系是用到的最多的一种关系,非常重要,在内存中反映为实体关系,映射到DB中主键外键关系,实体间的关联,即对外键的维护,关联关系的发生,即对外键数据的改变. 在这里就不赘述什么是外键什么是主键了. ...
- 深度学习3--caffe的安装(only CPU)
1. 本来按照视频走的,但是在cmake的时候报错,然后参考了这篇文章,稀里糊涂的就好了,总结就是把“视频/本文”说的依赖都安装上,就可以了,先安装opencv,再安装caffe第三方依赖 在安装ca ...
- 每天一个Linux命令(48)ping命令
ping命令用来测试主机之间网络的连通性. (1)用法: 用法: ping [参数] [主机名或IP地址] (2)功能: 功能: 确定网络和各外部主机的状态 ...
- DNS 域名解析原理
域名解析过程 1.在浏览器中输入www.qq.com域名,操作系统会先检查自己本地的hosts文件是否有这个网址映射关系,如果有,就先调用这个IP地址映射,完成域名解析. 2.如果hosts里没有这个 ...
- 在.h和.cpp中包含头文件的区别
1.在.h中包含头文件,是为了声明一系列这个头文件的变量等,可能会产生重复包含的问题: 2.在.cpp中包含头文件只是为了实现这个头文件或者使用其中的方法,不会有重复包含的问题,所以尽量在源文件中包含 ...