Python XML解析
参考:https://www.runoob.com/python/python-xml.html
什么是XML
XML 指可扩展标记语言(eXtensible Markup Language)。
XML被设计用来传输和存储数据。
XML是一套定义语义标记的规则,这些标记将文档分成许多部件并对这些部件加以标识。
它也是元标记语言,即定义了用于定义其他于特定领域有关的,语义的,结构化的标记语言的句法语言。
Python对XML的解析
常见的 XML 编程接口有 DOM 和 SAX,这两种接口处理 XML 文件的方式不同,当然使用场合也不同。
Python 有三种方法解析 XML,SAX,DOM,以及 ElementTree:
1,SAX(simple API for XML )
Python 标准库包含 SAX 解析器,SAX 用事件驱动模型,通过在解析XML的过程中触发一个个的事件并调用用户定义的回调函数来处理XML文件。
2,DOM(Document Object Model)
将 XML 数据在内存中解析成一个树,通过对树的操作来操作XML。
3,ELementTree(元素数)
ElementTree就像一个轻量级的DOM,具有方便友好的API。代码可用性好,速度快,消耗内存少。
注:因DOM需要将XML数据映射到内存中的树,一是比较慢,二是比较耗内存,而SAX流式读取XML文件,比较快,占用内存少,但需要用户实现回调函数(handler)。
本章节使用到的 XML 实例文件 movies.xml 内容如下:
<collection shelf="New Arrivals"> <movie title="Enemy Behind"> <type>War, Thriller</type> <format>DVD</format> <year>2003</year> <rating>PG</rating> <stars>10</stars> <description>Talk about a US-Japan war</description> </movie> <movie title="Transformers"> <type>Anime, Science Fiction</type> <format>DVD</format> <year>1989</year> <rating>R</rating> <stars>8</stars> <description>A schientific fiction</description> </movie> <movie title="Trigun"> <type>Anime, Action</type> <format>DVD</format> <episodes>4</episodes> <rating>PG</rating> <stars>10</stars> <description>Vash the Stampede!</description> </movie> <movie title="Ishtar"> <type>Comedy</type> <format>VHS</format> <rating>PG</rating> <stars>2</stars> <description>Viewable boredom</description> </movie> </collection>
本文介绍SAX和DOM两种方式
python使用SAX解析xml
SAX是一种基于实践取得的API
利用SAX解析文档涉及到两个部分:解析器和事件处理器。
解析器赋值读取XML文档,并像事件处理器发送事件,如元素开始跟元素结束事件。
而事件处理器则负责对事件作出相应,对传递的XML数据进处理。
1,对大型文件进行处理
2,只需要文件的部分内容,或者值需从文件中得到特定的信息。
3,想建立自己的对象模型时。
在python中使用sax方式处理xml要先引入xml.sax中的parse函数,还有xml.sax.handler中的ContentHandler类。
ContentHandler类方法介绍
characters(content)方法
调用事件:
从行开始,遇到标签之前,存在字符,content的值为这些字符串。
从一个标签,遇到下一个标签之前, 存在字符,content 的值为这些字符串。
从一个标签,遇到行结束符之前,存在字符,content 的值为这些字符串。
标签可以是开始标签,也可以是结束标签。
startDocument() 方法
文档启动的时候调用。
endDocument() 方法
解析器到达文档结尾时调用。
startElement(name, attrs)方法
遇到XML开始标签时调用,name是标签的名字,attrs是标签的属性值字典。
endElement(name) 方法
遇到XML结束标签时调用。
注意:一般使用startElement(name, attrs),characters(content),endElement(name) 这3个方法
startDoeument() 和endDocument()方法使用较少
make_parser方法
以下方法创建一个新的解析器对象并返回
xml.sax.make_parser( [parser_list] )
参数说明:
parser_list - 可选参数,解析器列表
parse方法
以下方法创建一个 SAX 解析器并解析xml文档:
xml.sax.parse( xmlfile, contenthandler[, errorhandler])
参数说明
xmlfile - xml文件名 contenthandler - 必须是一个ContentHandler的对象 errorhandler - 如果指定该参数,errorhandler必须是一个SAX ErrorHandler对象
parseString方法
parseString方法创建一个XML解析器并解析xml字符串:
xml.sax.parseString(xmlstring, contenthandler[, errorhandler])
参数说明
xmlstring - xml字符串 contenthandler - 必须是一个ContentHandler的对象 errorhandler - 如果指定该参数,errorhandler必须是一个SAX ErrorHandler对象
下面举例说明
创建一个ContentHandler类并使用该类处理XML文本
以下代码只在类里面使用一个print打印
# 只演示执行过程不实际处理数据start # 导入模块 import xml.sax # 创建一个Handler类继承xml.sax.ContentHandler类 class Handler(xml.sax.ContentHandler): def startDocument(self): print('startDocument...') def startElement(self,name,attr): print('startElement...') def characters(self,text): print('characters...') def endElement(self,name): print('endElement...') def endDocument(self): print('endDocument...') H = Handler() test_xml = '<a href="/">python</a>' xml_str = xml.sax.parseString(test_xml,H) # 输出如下 # startDocument... # startElement... # characters... # endElement... # endDocument... # 只演示执行过程不实际处理数据end
从输出可以明显看出执行的顺序为
# startDocument # startElement # characters # endElement # endDocument
以下代码演示各个方法参数对应的内容
# 演示参数start # 导入模块 import xml.sax # 创建一个Handler类继承xml.sax.ContentHandler类 class Handler(xml.sax.ContentHandler): def startElement(self,name,attr): print('startElement...') print('标签名字为 %s' %(name)) print('标签属性字典%s' %(attr.items())) def characters(self,text): print('characters...') print('标签内部内容为%s' %(text)) def endElement(self,name): print('endElement...') print('标签名字为 %s' %(name)) H = Handler() test_xml = '<a href="/">python</a>' xml_str = xml.sax.parseString(test_xml,H) # 输出如下 # startElement... # 标签名字为 a # 标签属性字典[('href', '/')] # characters... # 标签内部内容为python # endElement... # 标签名字为 a # 演示参数end
解析
本次分析的XML为 '<a href="/">python</a>' 标签名字为a 标签的写法为<str></str>名字即str 标签是属性为标签内定义的属性(可为空)即不定义属性,本次定了为href="/" attr为标签是属性字典,使用items即可显示内容 标签的内容及<a></a>之间的文本 本次为'python'
本次打开的是字符串,如果需要解析xml文档则把xml文档内容保存成文档然后使用以下方法调用
xml.sax.parse('test.xml',H)
Python解析实例
为了便于分析,本次把示例只保留一部电影
movies.xml
<collection shelf="New Arrivals"> <movie title="Enemy Behind"> <type>War, Thriller</type> <format>DVD</format> <year>2003</year> <rating>PG</rating> <stars>10</stars> <description>Talk about a US-Japan war</description> </movie> </collection>
解析代码如下
use_sax_xml.py
# 使用sax解析movies start import xml.sax class MoviesHandler(xml.sax.ContentHandler): def __init__(self): self.currentdata = '' self.type = '' self.format = '' self.year = '' self.rating = '' self.stars = '' self.description = '' def startElement(self,name,attr): self.currentdata = name if self.currentdata == 'movie': print('***movies***') title = attr['title'] print('Tiele:%s' %(title)) def characters(self,text): if self.currentdata == "type": self.type = text elif self.currentdata == "format": self.format = text elif self.currentdata == "year": self.year = text elif self.currentdata == "rating": self.rating = text elif self.currentdata == "stars": self.stars = text elif self.currentdata == "description": self.description = text def endElement(self,name): if self.currentdata == "type": print("Type:", self.type) elif self.currentdata == "format": print("Format:", self.format) elif self.currentdata == "year": print("Year:", self.year) elif self.currentdata == "rating": print("Rating:", self.rating) elif self.currentdata == "stars": print("Stars:", self.stars) elif self.currentdata == "description": print("Description:", self.description) self.currentdata = "" H = MoviesHandler() xml.sax.parse('movies.xml',H) # 使用sax解析movies end
运行输出如下
***movies*** Tiele:Enemy Behind Type: War, Thriller Format: DVD Year: 2003 Rating: PG Stars: 10 Description: Talk about a US-Japan war
使用调试模式查看执行过程
省略几步 依次处理了以下标签
<format>DVD</format> <year>2003</year> <rating>PG</rating> <stars>10</stars> <description>Talk about a US-Japan war</description>
处理完以上标签输出如下
由此可以知道使用SAX执行是逐条语句执行,不需要一次性读取文件至内存
优点是节约内存,缺点是需要执行写方法,效率低。
使用xml.dom解析xml
文件对象模型(Document Object Model,简称DOM),是W3C组织推荐的处理可扩展置标语言的标准编程接口。
一个 DOM 的解析器在解析一个 XML 文档时,一次性读取整个文档,把文档中所有元素保存在内存中的一个树结构里,之后你可以利用DOM 提供的不同的函数来读取或修改文档的内容和结构,也可以把修改过的内容写入xml文件。
python中用xml.dom.minidom来解析xml文件,示例如下:
使用DOM解析是一次性读取整个文档在内存中生成一个树结构,相比SAX使用更加简单,缺点是占用内存,但是目前服务器内存相对较大,从程序员节约写代码时间来看,可以优先选用DOM。
DOM解析方法参考:https://www.cnblogs.com/minseo/p/15187837.html
代码如下
# 使用dom解析movies start # 导入模块 import xml.dom.minidom # 打开xml文档 dom = xml.dom.minidom.parse('movies.xml') # dom.documentElement的到元素对象 movies = dom.documentElement.getElementsByTagName('movie') # getElementsByTagName('movie')从元素对象总查找标签名为movie的对象 # 得到的对象会组成一个对象列表,本次的对象只有一个 for movie in movies: print("*****Movie*****") # 如果对象有属性值title即电影名则打印 if movie.hasAttribute("title"): print("Title: %s" % movie.getAttribute("title")) # 在从得到的对象中间在搜索对应的标签名对象,本次找的的对象也是一个 # 使用[0]下标取得取得 # 使用firstChild.data获取对象的值打印 type = movie.getElementsByTagName('type')[0] print("Type: %s" % type.firstChild.data) format = movie.getElementsByTagName('format')[0] print("Format: %s" % format.firstChild.data) rating = movie.getElementsByTagName('rating')[0] print("Rating: %s" % rating.firstChild.data) description = movie.getElementsByTagName('description')[0] print("Description: %s" % description.firstChild.data) # 使用dom解析movies end
输出结果和使用SAX输出是一样的,只不过使用DOM方法代码更加简洁清晰