Python XML解析

xml 是一种扩展标记语言,实际开发中应用也比较广泛,经常用来在服务端与客户端间进行数据传输。下面我们来一起看下 python 中对 xml 的解析

1.python 解析 xml 的三种方式

python中有三种方法解析xml,分别为:SAX、DOM、ElementTree,建议使用第三种 ElementTree 解析 xml。

SAX用事件驱动模型,通过在解析XML的过程中触发对应的事件并调用用户定义的回调函数来处理XML文件。SAX是一种基于事件驱动的API,使用SAX解析XML会涉及到两个部分:解析器和事件处理器,解析器主要用于解析XML数据,并向事件处理器发送事件(startElement、endElement、characters等),而事件处理器主要用于对触发事件后作响应,对传递的XML数据进行处理。
优点:SAX使用流来读取xml数据,效率快,占用内存少
缺点:需要用户实现回调函数(Handler)

DOM是一次性将xml数据全部读取并解析成一个树放到内存中,通过对树的操作来操作XML。在解析时,一次性读取整个xml文档并把文档中所有的元素存放到内存中的一个树结构中,然后利用DOM提供的函数来读取或修改文档的内容和结构
优点:使用DOM的好处是不用对状态进行追踪,因为每一个节点都知道谁是它的父节点,谁是它的子节点
缺点:一次性将xml数据全部读取映射到内存中的树,效率低、占用内存

ElementTree类似一个轻量级的DOM,具有方便友好的API,代码可用性好,速度快,消耗内存少,推荐使用。

下面我们通过一个案例,分别用这三种方式来解析xml,看下每种方式是如何操作的。

有一个people.xml文件,内容如下

<?xml version="1.0" encoding="utf-8" ?>
<people>
    <person id="zhangsna">
        <name>张三</name>
        <age>18</age>
        <tel>18511908765</tel>
    </person>
    <person id="lisi">
        <name>李四</name>
        <age>20</age>
        <tel>15018984728</tel>
    </person>
    <person id="wangwu">
        <name>王五</name>
        <age>22</age>
        <tel>13067894532</tel>
    </person>
    <person id="zhaoliu">
        <name>赵六</name>
        <age>23</age>
        <tel>13067894532</tel>
    </person>
</people>

解析people文件中的内容,解析完成后将数据封装到一个Person对象中然后在控制台打印,打印时分别按年龄升序和按中文降序。Person 类如下

class Person:
    name=None
    age=None
    tel=None
    def __init__(self,name=None,age=None,tel=None):
        self.name=name
        self.age=age
        self.tel=tel

    def __repr__(self):  # 类似 java 中 的 toString()
        return '{0:20}{1:<5}{2:15}'.format(self.name, self.age, self.tel)

2.SAX 解析

sax 解析需要继承ContentHandler并重写其中的方法,ContentHandler类中常用方法如下

方法参数作用
startDocument()self文档启动时调用
endDocument()self解析器到达文档结尾时调用
startElement()self,name:元素名称,attrs:元素属性遇到XML开始标签时调用
endElement()self,name:元素名称遇到XML结束标签时调用
charactersself,content:文本内容读取元素内容时调用


sax 模块常用方法

方法作用
make_parser()创建一个新的解析器对象并返回
parse()创建一个 SAX 解析器并解析xml文档
parseString()创建一个XML解析器并解析xml字符串


代码:

import xml.sax  # 导入sax模块
from Person import Person   # 导入Person类

# 继承ContentHandler
class PeopleHandler(xml.sax.ContentHandler):
    # 初始化函数
    def __init__(self):
        self.person = None
        self.tag = None

    # 元素开始调用(name:元素名称,attrs:元素属性)
    def startElement(self, name, attrs):
        self.tag = name
        if name == 'person':
            self.person = Person()

    # 元素结束调用(name:元素名称)
    def endElement(self, name):
        if name == 'person':
            global people   # 引用外部的全局变量
            people.append(self.person)
            self.person = None
        self.tag = None

    # 读取元素内容时调用(content:文本内容)
    def characters(self, content):
        if "name" == self.tag:
            self.person.name = content
        if "age" == self.tag:
            self.person.age = int(content)
        if "tel" == self.tag:
            self.person.tel = content


people = []

# 创建一个 XMLReader
parser = xml.sax.make_parser()

# 关闭命名空间(不验证命名空间)
parser.setFeature(xml.sax.handler.feature_namespaces, 0)

# 重写 ContextHandler
parser.setContentHandler(PeopleHandler())

# 解析xml文档
parser.parse("people.xml")

print('{0:20}{1:<5}{2:15}'.format("姓名", "年龄", "手机号"))
print("--------------按年龄升序--------------")
for p in sorted(people, key=lambda x:x.age, reverse=False):
    print(p)
print("--------------按中文降序--------------")
people.sort(key=lambda x:x.name.encode("gbk"), reverse=True)  # 中文排序,需要进行编码为gbk或gb2312
for p in people:
    print(p)

运行结果:

姓名                  年龄   手机号            
--------------按年龄升序--------------
张三                  18   18511908765    
李四                  20   15018984728    
王五                  22   13067894532    
赵六                  23   13067894532    
--------------按中文降序--------------
赵六                  23   13067894532    
张三                  18   18511908765    
王五                  22   13067894532    
李四                  20   15018984728    

3.DOM 解析

# 导入模块
from xml.dom.minidom import parse
from Person import Person

people = []

# 使用minidom解析器打开 XML 文档
domTree = parse("people.xml")

# 获取文档元素
collection = domTree.documentElement;

# 获取集合中的 person 元素
person = collection.getElementsByTagName("person")
for e in person:
    # 获取所有的id元素的属性
    # idAttrs = e.attributes['id']
    # print(idAttrs)

    # 获取所有的name元素
    # elements = e.getElementsByTagName("name")[0]
    # print(elements)

    # 获取所有的name元素的文本值
    # text = e.getElementsByTagName("name")[0].childNodes[0].data;
    # print(text)

    name = e.getElementsByTagName("name")[0].childNodes[0].data
    age = e.getElementsByTagName("age")[0].childNodes[0].data
    tel = e.getElementsByTagName("tel")[0].childNodes[0].data

    p = Person(name, age, tel)
    people.append(p)

print('{0:20}{1:<5}{2:15}'.format("姓名", "年龄", "手机号"))
print("--------------按年龄升序--------------")
for p in sorted(people, key=lambda x:x.age, reverse=False):
    print(p)
print("--------------按中文降序--------------")
# 中文排序,需要进行编码为gbk或gb2312
people.sort(key=lambda x:x.name.encode("gbk"), reverse=True)  
for p in people:
    print(p)

运行结果与SAX相同

4.ElementTree

ElementTree 在 Python 中有两种实现
一种是纯 Python 实现:xml.etree.ElementTree
另一种是 C 语言实现:xml.etree.cElementTree
建议使用 C 语言 实现的 ElementTree,因为它速度更快,占用内存更少
在程序中导入模块时这样写(如果C语言实现的不能使用再使用纯Python实现的)

try:
    import xml.etree.cElementTree as ET
except ImportError:
    import xml.etree.ElementTree as ET

ElementTree 中 常用方法

方法作用
parse(xmlfile)加载xml文件
fromstring(xmltext)加载xml文件
findall()获取指定的所有节点
find()获取指定的节点
getchildren()获取儿子节点
getiterator()获取指定的所有节点,与findall()类似


示例:

root = ET.parse("people.xml")
print("------------findall()------------")
persons1 = root.findall("person")
print(persons1)

print("----------getiterator()----------")
persons2 = root.getiterator("person")
print(persons2)

print("----------getchildren()----------")
for node in persons2:
    node_child = node.getchildren()[0]
    print(node_child.tag + " => " + node_child.text)

运行结果:

------------findall()------------
[<Element 'person' at 0x00000000020F02C8>, <Element 'person' at 0x0000000002585908>, <Element 'person' at 0x00000000025A1138>, <Element 'person' at 0x00000000025A1278>]
----------getiterator()----------
[<Element 'person' at 0x00000000020F02C8>, <Element 'person' at 0x0000000002585908>, <Element 'person' at 0x00000000025A1138>, <Element 'person' at 0x00000000025A1278>]
----------getchildren()----------
name => 张三
name => 李四
name => 王五
name => 赵六

ElementTree 中 常用属性

属性作用
attrib获取节点的属性及属性值(以元祖的形式返回)
tag获取节点名称
text获取节点的文本值


示例

root = ET.parse("people.xml")

persons = root.findall("person")

for node in persons:
    print(node.attrib)
    print(node.tag)
    name = node.find("name")
    print(name.text)

运行结果:

{'id': 'zhangsna'}
person
张三
--------------------
{'id': 'lisi'}
person
李四
--------------------
{'id': 'wangwu'}
person
王五
--------------------
{'id': 'zhaoliu'}
person
赵六
--------------------

ElementTree 的常用方法及属性我们了解后,接着实现我们最开始的案例,代码如下,运行结果与 SAX 相同

from Person import Person
try:
    import xml.etree.cElementTree as  ET
except ImportError:
    import xml.etree.ElementTree as ET

people = []

# 加载people.xml文件
root = ET.parse("people.xml")

# 获取所有person节点
persons = root.findall("person")

for node in persons:
    name = node.find("name").text
    age = node.find("age").text
    tel = node.find("tel").text

    p = Person(name, age, tel)
    people.append(p)

print('{0:20}{1:<5}{2:15}'.format("姓名", "年龄", "手机号"))
print("--------------按年龄升序--------------")
for p in sorted(people, key=lambda x:x.age, reverse=False):
    print(p)
print("--------------按中文降序--------------")
# 中文排序,需要进行编码为gbk或gb2312
people.sort(key=lambda x:x.name.encode("gbk"), reverse=True)  
for p in people:
    print(p)
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值