我们知道,在Web传输过程中有很多结构化数据,xml就是其中的一种。它以其简单、易理解和结构化而著称,虽然在数据传输过程中它占用的空间要比二进制数据多,但它的可读性和简单的组织结构却是二进制文件不能比较的。
对于开发者来讲xml文件优点很多
xml文档结构使得开发人员能够更加得心应手地来控制数据的存储和传输。今天,我们用一个案例来详细了解一下,使用Python如何解析一个xml文档。
如何解析一个xml文档
什么是xml文档
xml是可扩展标记语言(eXtensible Markup Language ( XML)),是一种用于标记电子文件使其具有结构性的标记语言,被设计用来传输和存储数据。比如,我们有下面一行数据:
[{id:001, name: Lucy, age: 18, country: 'English', Address: BeiJing, Speciality: {'Ball': ['basketball', 'football'], 'Run': ['sprint']}]},
{id:002, name: Boby, age: 20, country: 'France', Address: GuangZhou}, Speciality: {'Ball': ['ping-pang', 'football'], 'Run': ['Long-distance run']}]]
类似我们的列表里面装了一个字典、字典又装了列表等等这样的Python类型。
不同数据结构反映不同内容
大概意思就是存储了两个人Lucy和Boby,分别记录了id、姓名、年龄、国籍、地址、特长(球类、跑步)等信息。如果放在Python中,开发人员很容易理解它的意思。但这段描述可读性和结构化程度并不高,我们可以使用XML标记语言标记成这样(当然你还也可以使用json或者类似YAML这样的结构进行标记也是可以滴)
xml描述上面的信息
如何组织xml文档结构
在组织xml文档结构时,侧重点不同组织方式也不同。比如,我们上面将“country”国籍信息作为一个‘Person’的主要属性,我们的程序侧重点是需要方便检索不同国籍的人。当然,你也可以将‘country’作为name的一个属性放到name标签中,至于如何组织,看你需要从xml获取什么信息?今天,我们暂时将上面的Python对象表示成上图中的xml结构。
开发人员如何组织一份xml文档
我们知道,xml文档是有别于html文档的,html文档都是标准化的标签结构,而xml对于标签进行了扩展,也就是说你可以使用任意的标签名称和属性值。xml文档的解析比html文档解析更有难度,我们先来看下本例需要解析哪些内容?
提取哪些信息
使用Python可以从xml文件中提取出任何有用的信息,比如,我们今天想知道下面信息(例子中只有两个,当然你还可以放更多人进去,我们只是举个例子)
xml文档中存了多少人的信息;把国籍为'France'的人找出来;把住在广州的人找出来;找出特长是乒乓球的人;输出所有人的信息从上面的例子基本就可以掌握xml文档的解析方法,我们逐一来实现……
今日为大家推荐一本Python学习的书籍,国外大牛写得,关于标准库的。我正在看,写得挺不错,喜欢阅读正版书的小伙伴赶紧入手吧。
如何解析并提取信息
我们知道,对于html文档,我们一般使用BeautifulSoup库解析其中的内容。而xml文档有没有模块进行提取信息呢?
有没有呢?
Python提供了哪些方法
Python提供了三种解析xml文档的方法,分别是SAX,DOM和 ElementTree,其中SAX和DOM处理方式比较复杂,今天就不做探讨,我们使用ElementTree进行解析,这个类本质上类似一个轻量级的DOM。比较其它两种方法,使用ElementTree具有方便友好的API,代码可用性好,速度快,消耗内存少。
xml定义的ElementTree是一个树状结构
使用xml.etree.ElementTree类中的parse()方法
# 直接导入模块中的方法
from xml.etree.ElementTree import parse
# 打开xml文件
f = open('demo.xml')
# 创建一个ElementTree对象实例
et = parse(f)
# 得到对象的根节点
root = et.getroot()
我们需要的所有信息都在这个root里面
>>>print(type(root))
root是et(ElementTree)的子类Element
我们来看下Element有哪些属性?
>>>print(root.tag)
PersonInfo # 返回标签名称
>>>print(root.attrib)
{} # 返回标签属性字典,类似Person中的country属性
>>>print(root.text) # 字符串形式返回标签之间的文本内容,本次返回为空
需要知道
下面是重点
递归查找所有子节点:obj.iter('Name')
非递归查找所有子节点:obj.findall('Name')
逐条解析
1.xml文档中存了多少人的信息
我们看到,Person标签是在PersonInfo标签下,可以理解为Person标签是PersonInfo标签的子类,解析这条需求类似于找到root中有多少个子类。
可以使用root.getchildren()返回root的子类。需要说明的是根据文档提示,getchildren()这个方法在以后Python版本中将会被废弃,因此尽量少用,我们直接使用len(root)就可以知道root下有多少个子类(直接子类对象)。
print(len(root))
>>>2
2.国籍为'France'的人是?
找出Person标签属性为'France'的人,使用root.findall('Person[@country
="France"]')方法,findall查找符合要求的所有子类元素并返回,find()只返回查找到的第一个元素。
p = root.findall('Person[@country]')
for item in p:
print(item.find('name').text)
>>>Boby
返回正确。
3.住在广州的人有哪些?
其实就是找到Person标签中addr标签text为GuangZhou的人
for item in root;
if item.find('addr').text == 'GuangZhou':
print(item.find('name').text)
>>>Boby
成功返回
4.找出特长是乒乓球的人
其实就是找到Ball标签中item标签为'ping-pong'的人
for item in root:
for i_item in item.iter():
if i_item.text == 'ping-pong':
print(item.find('name').text)
这里的item标签在第4层嵌套中,我们不好获取,因此先循环遍历root,使得item作为父节点,这样就能获取到name标签的text属性,这里好好琢磨下……
5.输出所有人信息
我们依次遍历输出:
for n, item in enumerate(root):
# item就是每个人的信息
print('第{}个人的信息:'.format(n+1))
print("ID:{}\n姓名:{}\n年龄:{}\n地址:{}\n"
"特长:\n\t球类:{}\n\t跑步:{}".format(
item.find('id').text, item.find('name').text,
item.find('age').text, item.find('addr').text,
' '.join([i.text for i in item.find('Speciality').find('Ball')]),
' '.join([i.text for i in item.find('Speciality').find('Run')]),
))
这样输入如下:
提取到人物信息
我们通过5个例子详细介绍了xml数据解析的方法。当然,使用SAX,DOM还是可以成功解析的,感兴趣的朋友们自己学习哦。
xml其它解析方式自己研究吧
今天的技能Get到了吗?想学Python的小伙伴关注我,会持续推出有关Python的知识点和实战相关内容。
转载请注明出处,百家号:Python高手养成