Python的xml.sax模块是基于SAX(Simple API for XML)规范实现的XML解析工具,采用事件驱动模式工作,解析过程中会触发对应的事件,开发者只需要编写事件处理逻辑即可完成XML内容的提取和处理。

xml.sax模块核心组件
使用xml.sax模块前需要先了解几个核心组件:
- xml.sax.parse:用于解析XML文件或类文件对象,是启动解析的入口函数。
- xml.sax.make_parser:创建SAX解析器实例,可自定义解析器配置。
- xml.sax.handler.ContentHandler:内容处理基类,开发者需要继承该类并重写对应的事件方法,实现自己的解析逻辑。
自定义ContentHandler子类
ContentHandler提供了多个事件回调方法,常用的包括:
startDocument():解析到XML文档开头时触发。endDocument():解析到XML文档结尾时触发。startElement(name, attrs):解析到元素开始时触发,name是元素名,attrs是元素的属性集合。endElement(name):解析到元素结束时触发。characters(content):解析到元素内的文本内容时触发。
下面是一个自定义解析器的示例,用于解析一个存储书籍信息的XML文件:
import xml.sax
from xml.sax.handler import ContentHandler
# 自定义内容处理器
class BookHandler(ContentHandler):
def __init__(self):
self.current_tag = None
self.book_data = []
self.current_book = {}
def startElement(self, name, attrs):
self.current_tag = name
# 如果是book元素开始,初始化当前书籍字典
if name == "book":
self.current_book = {}
# 获取book元素的id属性
if "id" in attrs:
self.current_book["id"] = attrs["id"]
def endElement(self, name):
# 如果是book元素结束,将当前书籍信息存入列表
if name == "book":
self.book_data.append(self.current_book)
self.current_tag = None
def characters(self, content):
# 去除空白字符,避免解析到无意义的换行空格
content = content.strip()
if self.current_tag and content:
self.current_book[self.current_tag] = content
# 待解析的XML内容
xml_content = """<?xml version="1.0" encoding="UTF-8"?>
<library>
<book id="1">
<title>Python编程入门</title>
<author>张三</author>
<price>59.9</price>
</book>
<book id="2">
<title>XML解析实战</title>
<author>李四</author>
<price>49.9</price>
</book>
</library>
"""
# 创建解析器
parser = xml.sax.make_parser()
# 关闭命名空间处理
parser.setFeature(xml.sax.handler.feature_namespaces, 0)
# 实例化自定义处理器
handler = BookHandler()
parser.setContentHandler(handler)
# 解析XML内容,这里使用parseString解析字符串,也可以传入文件路径用parse方法
xml.sax.parseString(xml_content.encode("utf-8"), handler)
# 输出解析结果
for book in handler.book_data:
print(f"书籍ID:{book.get('id')}")
print(f"书名:{book.get('title')}")
print(f"作者:{book.get('author')}")
print(f"价格:{book.get('price')}")
print("-" * 20)
解析本地XML文件
如果需要解析本地存储的XML文件,只需要将parseString替换为parse方法,传入文件路径即可:
import xml.sax
from xml.sax.handler import ContentHandler
class BookHandler(ContentHandler):
# 同上方的BookHandler实现
def __init__(self):
self.current_tag = None
self.book_data = []
self.current_book = {}
def startElement(self, name, attrs):
self.current_tag = name
if name == "book":
self.current_book = {}
if "id" in attrs:
self.current_book["id"] = attrs["id"]
def endElement(self, name):
if name == "book":
self.book_data.append(self.current_book)
self.current_tag = None
def characters(self, content):
content = content.strip()
if self.current_tag and content:
self.current_book[self.current_tag] = content
# 解析本地文件,假设文件名为books.xml,和脚本在同一目录
parser = xml.sax.make_parser()
parser.setFeature(xml.sax.handler.feature_namespaces, 0)
handler = BookHandler()
parser.setContentHandler(handler)
xml.sax.parse("books.xml", handler)
for book in handler.book_data:
print(book)
使用注意事项
- xml.sax是事件驱动解析,不会保留整个XML的树结构,如果需要频繁随机访问XML节点,更适合使用xml.etree.ElementTree模块。
- 解析过程中
characters方法可能会被多次调用,比如文本内容中包含换行时,需要做好内容的拼接和去空白处理。 - 如果XML文件包含命名空间,需要开启对应的解析器特性,避免元素名解析异常。
- 处理大型XML文件时,xml.sax的内存占用远低于DOM解析方式,是处理大文件的首选方案。