内容我们通过一个例子详解了Python解析xml文档的方法(参见Web传输和存储数据结构化,xml可轻松实现,用Python如何解析它?)。今天,我们同样使用一个案例来了解下xml文档的读取和写入操作,以加深印象。千万别走开,前面是对之前知识的回顾,如果你对案例更感兴趣,请直接到文末看。
回顾下就当加深印象了今天,我们同样使用xml.etree.ElementTree模块下的parse()方法来进行xml文件的读写操作。
为什么使用xml.etree模块
我们知道,Python的xml模块下还有很多接口可以用来处理xml文档,比如,xml.dom、xml.sax模块,都提供了用于处理xml文件的接口。我们为什么就使用etree模块呢?这是因为,其它两个模块的处理方式存在一定的缺陷:
另外两个库都不是完美解决方案首先,xml.dom模块在处理文档之前,会将xml文件构建好的树状数据存储在内存中,这样既浪费了内存空间,又增加了系统开销,而且当数据量大时,程序运行会非常缓慢;
对Python来说慢是很严重的问题对比xml.sax模块,使用过这个模块的人都知道,虽说该模块实现了SAXAPI,运行速度和占用内存方面比xml.dom都要好,但是它在处理xml文件时,过程是很复杂的(对比etree模块来说),对于开发人员来讲,它没有etree提供的接口便利。
逛超市和逛菜市场的区别因此,我们今天仍使用xml.etree模块来处理xml文件。对其它两个模块感兴趣的小伙伴可以私底下好好研究下,说不定你还能发现一些好的算法呢?
etree模块处理机制
我们在上篇解析中提到了xml文件的解析,解析之前肯定要先读取了,但是上篇内容并没有很好的做出说明。今天我们来详细梳理下:
接触过Linux的小伙伴肯定知道,Linux文件系统结构就像一个倒立的树形结构,这种结构的优点是层次清晰,便于检索和操作文件。
更像是一颗倒着的树xml.etree模块在处理xml文档时也采用类似的结构,它将一个xml文档定义为一个标签树结构,整个标签树我们叫ElementTree,它包含了该xml文档的内容,我们可以使用ElementTree.getroot()方法获取标签树最上层的元素,该元素称之为根节点,本质上来讲它仍是一个节点,即Element,它和ElementTree中的每一个节点的操作都是一样的,区别在于它没有父节点。
理解节点之间的关系是主线从上面的分析我们很容易理解,对于整个xml文档的读取、写入、修改,我们在ElementTree层面上进行;而对于节点Element的操作,我们是在Element层面上展开的。因此,如果能熟练掌握这两个对象的接口,就基本能够读写xml文件了。千万别走开,下面有案例哦!
读取并解析xml文档的一般步骤
importxml.etree.ElementTree
et=ElementTree.ElementTree(file=demo.xml)
root=et.getroot()
root是一个Element对象,它具有以下属性:
1.tag:返回元素的标签名
2.attrib:以字典形式返回属性名和值
它提供的方法有:
print([iforiindir(root)ifnoti.startswith(_)],end=)
[append,attrib,clear,extend,find,findall,findtext,get,getchildren,getiterator,insert,items,iter,iterfind,itertext,keys,makeelement,remove,set,tag,tail,text]
这样一些方法,其实常用的就那么几个,下文会提到,这些方法也不需要记住,但这个处理步骤如果能记住就更好了。
1.根节点遍历解析其它节点
这里的root本身是一个可迭代对象,它可以直接遍历子元素。如下
forelinroot:
print(el.tag)
也可以使用索引找到需要的元素
root[0].tag#返回root下的第一个元素标签
2.查找需要的元素
使用find()、findall()、,iterfind()等进行查找,这些函数的查找范围是下一层子节点,它们不会去找孙子节点或更下一层节点
find(tagName):返回第一个匹配的元素
findall(tagName):返回当前元素下一级所有匹配的元素列表
iterfind(tagName):作用和findall一样,但是它返回一个生成器对象
3.查找当前元素下的所有元素
root.iter()#列出根元素下所有子节点列表,返回一个迭代器对象
root.iter(tagName) #列出所有标签名为tagName的子节点,是迭代器对象
4.正则表达式匹配
*:表示所有节点,如:root.find(a/*)表示查找路径a下面的所有子节点
.:表示当前元素,如:root.find(./*)表示查找当前元素下的所有子节点
//:表示当前层级,如:root.findall(.//a):查找当前目录下任意层级的标签名为a的子元素
..:表示上层节点,如:root.findall(.//a/..):查找当前目录下任意层级的标签名为a的子元素的父元素
[
attrib]:表示根据指定的属性搜索元素[
attrib=value]:表示根据给定属性名搜索元素,如:root.findall(a[type=txt]):找到所有type为txt的a标签[tag]:表示子元素标签,如root.findall(a):找到包含子元素为b的a标签
[position]:还可以i根据元素位置找相应的元素,从1开始:root.findall(a[1])root.findall(a[last()-1]):找到倒数第二个元素
上面就是基本的解析元素的步骤了。这就完了?No,今天的内容才刚开始,我们通过一个案例来展示如何写入xml文件。
一个例子
例子是这样的,我们有一份Excel文件,里面记录了一些学生的基本信息,我们将Excel文件中的内容读取出来,然后存储到xml文件中去。
举例来说明读取Excel文件需要使用到xlrd模块(第三方模块需要安装)
Excel文件格式如下
Excel表格结构废话不说,直接上代码了。如下
Excel文件数据以xml格式返回pretty()函数是用于格式化输出的,方法可借鉴,这是一个递归函数。
剩余代码程序运行后,生成的xml文件如下
程序最终实现好了,今天的内容就到这里了,我们详细梳理了xml文件的读写操作方式,并通过一个案例完美展示了从Excel文件中读取数据转化为xml文档的过程。其实,如果程序有需要,你甚至可以完成诸如json转xml或者是csv文件与xml文档之间的转化,都是可以的,感兴趣的小伙伴们试试看,就当是个练习内容。欢迎大家留言讨论,