转载了这么多的文章,终于可以写一点自己的东西了。初学Python不久,程序中不当之处还请各位看官不吝赐教。
本文中很多地方都是参考了其他人的博文,具体的也不甚清楚到底参考了哪些,在此仅列出一个大概吧。绿色背景表示含有链接。
感谢gaodeyue,他的例程写的很好。我直接参考了他的DOM构建和解析XML文档的程序写了一个我自己的XML文档。另外的那篇Python处理XML数据之SAX篇我想也还不错,不过现在觉得还是没必要学,时间又稍微有点紧,所以先不弄了,转载过来好了。其实想写这篇博文也是因为看了他的Python处理XML数据之DOM篇才有这个想法的。非常感谢。
感谢yueguanghaidao,在网上游荡了好久,发现用ElementTree来解析XML文档的很多,但是用ElementTree来生成XML文件的真滴不多,而且很杂乱,然后我就找到了yueguanghaidao的这篇博文,参照着把ElementTree生成XML文档的程序给写出来了。同样非常感谢。本博文的第二大段文字“Python有三种方法解析XML”亦是来自于yueguanhaidao,在此再次表示感谢。
感谢大CC,引用了他写的美化程序,非常的好用,非常谢谢!
注:我所使用的Python版本为2.7.3
Python提供了两种XML支持:
第一种是支持两种XML解析的行业标准方法——SAX和DOM 。 SAX(Simple API for XML ,用于XML的简单API)以事件处理为基础,按照遇到XML元素的顺序读取XML文档,触发处理函数来执行处理。DOM (Document Object Model ,文档对象模型)构建表示整个XML文档的树结构。树结构构建完成后, DOM将提供一个遍历树和提取数据的接口。SAX和DOM API都不是源自Python ,Python只是复制了为Java和JavaScript开发的接口。
第二种是支持特定于Python的XML解析方住。尽管可以使用SAX和DOM接口处理XML ,但是标准库中最方便的编程接口还是ElementTree接口。这种方住充分利用了Python的语言特点,大部分用户发现它比SAX或DOM要更加简单快捷。本文将讨论这3 种XML解析方法,重点讨论ElementTree方法。
这里建议读者只关注基本的XML数据解析。Python还包括与实现新类型解析、从头构建XML文档等方面有关的XML模块。此外,各种第三方扩展插件扩展了Python的功能,添加了其他XML功能,如支持XSLT和XPATH。更多信息的链接,请参见http://wiki.python.org/moin/PythonXml。
python有三种方法解析XML:SAX、DOM以及ElementTree
1.SAX (simple API for XML )
pyhton 标准库包含SAX解析器,SAX是一种典型的极为快速的工具,在解析XML时,不会占用大量内存。但是这是基于回调机制的,因此在某些数据中,它会调用某些方法进行传递。这意味着必须为数据指定句柄,以维持自己的状态,这是非常困难的。
2.DOM(Document Object Model)
与SAX比较,DOM典型的缺点是比较慢,消耗更多的内存,因为DOM会将整个XML数读入内存中,并为树中的第一个节点建立一个对象。使用DOM的好处是你不需要对状态进行追踪,因为每一个节点都知道谁是它的父节点,谁是子节点。但是DOM用起来有些麻烦。
3.ElementTree(元素树)
ElementTree就像一个轻量级的DOM,具有方便友好的API。代码可用性好,速度快,消耗内存少,这里主要介绍ElementTree。
下面是一个简单的XML例子,其文件名为ep1.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <bookstore>
- <book category="COOKING">
- <title language="English">Everyday Italian</title>
- <author>Giada De Laurentiis</author>
- <year>2005</year>
- <price>30.00</price>
- </book>
- <book category="JUVENILE">
- <title language="English">Harry Potter</title>
- <author>J K. Rowling</author>
- <year>2005</year>
- <price>29.99</price>
- </book>
- <book category="WEB">
- <title language="English">Learning XML</title>
- <author>Erik T. Ray</author>
- <year>2003</year>
- <price>39.95</price>
- </book>
- </bookstore>
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book category="COOKING">
<title language="English">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
<book category="JUVENILE">
<title language="English">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
<book category="WEB">
<title language="English">Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<price>39.95</price>
</book>
</bookstore>
在这段XML中有三个book元素,每个book又有category属性和title、author、year和price四个元素,其中title元素含有language属性。可以看出,XML表现数据非常直观,即使没学过也能很快的理解,相比之下DOM就要稍微复杂一点了。
Python处理XML之DOM篇这一部分主要讨论如何用xml.dom模块来处理上述XML文件
下面我们会用python的DOM编程接口来生成上面的bookstoreXML数据,在此之前,你需要对DOM又一个简单的认识,如果你已经知道DOM了,可以直接跳到code部分。
在DOM中,文档由不同的节点组成。<book>、<title>这些在’<>’中的叫做元素节点,category这种以'name=value’形式出现在’<>’中的是属性节点,'Harry Potter’、'2005'这些又叫做文本节点(注意:文本本身也是节点,而不是外层元素节点的值,<name>节点的值是null!)。除此以外,节点和节点之间还存在父子关系,比如<bookstore>是整个文档的根节点,它下面有三个book元素子节点,每个book节点又有一个category属性子节点和title、author、year和price四个元素子节点,title元素节点下有一个属性节点language和一个文本子节点Harry Potter,最终一个DOM文档就由各种节点构成一颗节点树。OK,一般来说掌握这些知识足够了,如果你想要系统的学习DOM,请参考W3C的DOM标准。
首先编程生成ep1.xml文件
- # -*- coding:UTF-8 -*-
- from xml.dom import getDOMImplementation
- def create_element_with_text(document,tagname,text):
- "创建一个元素节点,该节点只有一个文本子节点"
- #创建元素节点和文本节点
- elementNode = document.createElement(tagname)
- textNode = document.createTextNode(text)
- # 将文本节点作为元素节点的子节点
- elementNode.appendChild(textNode)
- return elementNode
- def create_bookstore_xml(filename):
- impl = getDOMImplementation()
- # 创建文档对象,文档对象用于创建各种节点。
- # 注意这个文档不是指XML文件,而是DOM文档
- doc = impl.createDocument(None, # namespaceUri
- "bookstore", # qualifiedName
- None) # doctype
- top_element = doc.documentElement # 得到根节点
- # 定义要转换的数据
- bookstore = [{'category':'COOKING', 'title':'Everyday Italian', 'language':'English', 'author':'Giada De Laurentiis', 'year':2005,'price':30.00},
- {'category':'JUVENILE', 'title':'Harry Potter', 'language':'English', 'author':'J K. Rowling', 'year':2005,'price':39.99},
- {'category':'WEB', 'title':'Learning XML', 'language':'English', 'author':'Erik T. Ray', 'year':2003,'price':39.95}]
- for book in bookstore:
- sNode = doc.createElement('book')
- # 为book添加categroy属性节点,注意属性值需要转化成string类型
- sNode.setAttribute('category', book['category'])
- # 给book节点添加四个元素子节点,注意year和price要转成string
- titleNode = create_element_with_text(doc, 'title', book['title'])
- titleNode.setAttribute('language', book['language'])
- authorNode = create_element_with_text(doc, 'author', book['author'])
- yearNode = create_element_with_text(doc, 'year', str(book['year']))
- priceNode = create_element_with_text(doc, 'price',str(book['price']))
- sNode.appendChild(titleNode)
- sNode.appendChild(authorNode)
- sNode.appendChild(yearNode)
- sNode.appendChild(priceNode)
- # 将遍历的student节点添加到根节点下
- top_element.appendChild(sNode)
- # 最后,将DOM文档写到文件中保存
- xml_file = open(filename, 'w')
- print doc.toprettyxml()#美化XML输出
- doc.writexml(xml_file, addindent=' '*4, newl='\n', encoding='utf-8')
- if __name__ == '__main__':
- create_bookstore_xml('bookDOM.xml')
# -*- coding:UTF-8 -*-
from xml.dom import getDOMImplementation
def create_element_with_text(document,tagname,text):
"创建一个元素节点,该节点只有一个文本子节点"
#创建元素节点和文本节点
elementNode = document.createElement(tagname)
textNode = document.createTextNode(text)
# 将文本节点作为元素节点的子节点
elementNode.appendChild(textNode)
return elementNode
def create_bookstore_xml(filename):
impl = getDOMImplementation()
# 创建文档对象,文档对象用于创建各种节点。
# 注意这个文档不是指XML文件,而是DOM文档
doc = impl.createDocument(None, # namespaceUri
"bookstore", # qualifiedName
None) # doctype
top_element = doc.documentElement # 得到根节点
# 定义要转换的数据
bookstore = [{'category':'COOKING', 'title':'Everyday Italian', 'language':'English', 'author':'Giada De Laurentiis', 'year':2005,'price':30.00},
{'category':'JUVENILE', 'title':'Harry Potter', 'language':'English', 'author':'J K. Rowling', 'year':2005,'price':39.99},
{'category':'WEB', 'title':'Learning XML', 'language':'English', 'author':'Erik T. Ray', 'year':2003,'price':39.95}]
for book in bookstore:
sNode = doc.createElement('book')
# 为book添加categroy属性节点,注意属性值需要转化成string类型
sNode.setAttribute('category', book['category'])
# 给book节点添加四个元素子节点,注意year和price要转成string
titleNode = create_element_with_text(doc, 'title', book['title'])
titleNode.setAttribute('language', book['language'])
authorNode = create_element_with_text(doc, 'author', book['author'])
yearNode = create_element_with_text(doc, 'year', str(book['year']))
priceNode = create_element_with_text(doc, 'price',str(book['price']))
sNode.appendChild(titleNode)
sNode.appendChild(authorNode)
sNode.appendChild(yearNode)
sNode.appendChild(priceNode)
# 将遍历的student节点添加到根节点下
top_element.appendChild(sNode)
# 最后,将DOM文档写到文件中保存
xml_file = open(filename, 'w')
print doc.toprettyxml()#美化XML输出
doc.writexml(xml_file, addindent=' '*4, newl='\n', encoding='utf-8')
if __name__ == '__main__':
create_bookstore_xml('bookDOM.xml')
可以看出,使用DOM的好处是可以很自由的调整各节点之间的关系,面对频繁添加或者删除节点的需求时,可以轻松地用DOM来解决,SAX在这方面显得非常乏力。然而,DOM的缺点是在解析时需要把整个XML文档映射为内存中的DOM树,如果文件很大的话,构建DOM树就会非常耗资源了。
下面我们就来看看怎么解析刚才生成的XML文件,重新构造出bookstore列表。这里用到了xml.dom.minidom模块中的parse方法。
- from xml.dom import minidom
- def get_node_text(node):
- # 得到元素的文本子节点中的内容,strip用于取出文本两头的空白字符
- return node.childNodes[0].nodeValue.strip()
- def parse_bookstore_xml(filename):
- # 利用minidom模块将XML文件解析成DOM文档对象
- doc = minidom.parse(filename)
- top_element = doc.documentElement
- bookstore = []#列表
- books = top_element.getElementsByTagName('book')
- for node in books:
- book = {} #字典
- book['category'] = node.getAttribute('category')
- book['title'] = get_node_text(node.getElementsByTagName('title')[0])
- #下面两句是做测试用的
- #print node.getElementsByTagName('title')[0].hasAttributes()
- #print node.getElementsByTagName('title')[0].hasAttribute('language')
- book['language']=node.getElementsByTagName('title')[0].getAttribute('language')
- book['author'] = get_node_text(node.getElementsByTagName('author')[0])
- book['year'] = get_node_text(node.getElementsByTagName('year')[0])
- book['price'] = get_node_text(node.getElementsByTagName('price')[0])
- bookstore.append(book)
- return bookstore
- if __name__ == '__main__':
- bookstore = parse_bookstore_xml('ep1.xml')
- print 'bookstore:'
- i=1
- for book in bookstore:
- print 'book%s'%i
- print book
- i=i+1
- for key in book:
- print ' %s : %s' % (key,book[key])
from xml.dom import minidom
def get_node_text(node):
# 得到元素的文本子节点中的内容,strip用于取出文本两头的空白字符
return node.childNodes[0].nodeValue.strip()
def parse_bookstore_xml(filename):
# 利用minidom模块将XML文件解析成DOM文档对象
doc = minidom.parse(filename)
top_element = doc.documentElement
bookstore = []#列表
books = top_element.getElementsByTagName('book')
for node in books:
book = {} #字典
book['category'] = node.getAttribute('category')
book['title'] = get_node_text(node.getElementsByTagName('title')[0])
#下面两句是做测试用的
#print node.getElementsByTagName('title')[0].hasAttributes()
#print node.getElementsByTagName('title')[0].hasAttribute('language')
book['language']=node.getElementsByTagName('title')[0].getAttribute('language')
book['author'] = get_node_text(node.getElementsByTagName('author')[0])
book['year'] = get_node_text(node.getElementsByTagName('year')[0])
book['price'] = get_node_text(node.getElementsByTagName('price')[0])
bookstore.append(book)
return bookstore
if __name__ == '__main__':
bookstore = parse_bookstore_xml('ep1.xml')
print 'bookstore:'
i=1
for book in bookstore:
print 'book%s'%i
print book
i=i+1
for key in book:
print ' %s : %s' % (key,book[key])
运行后得到如下结果:
- bookstore:
- book1
- category : COOKING
- language : English
- author : Giada De Laurentiis
- price : 30.00
- title : Everyday Italian
- year : 2005
- book2
- category : JUVENILE
- language : English
- author : J K. Rowling
- price : 29.99
- title : Harry Potter
- year : 2005
- book3
- category : WEB
- language : English
- author : Erik T. Ray
- price : 39.95
- title : Learning XML
- year : 2003
bookstore:
book1
category : COOKING
language : English
author : Giada De Laurentiis
price : 30.00
title : Everyday Italian
year : 2005
book2
category : JUVENILE
language : English
author : J K. Rowling
price : 29.99
title : Harry Potter
year : 2005
book3
category : WEB
language : English
author : Erik T. Ray
price : 39.95
title : Learning XML
year : 2003
解析代码中最关键的就是minidom模块的parse方法以及DOM节点对象的getElementsByTagName和childNodes方法,如果这还不足以满足你的需求,请参考python标准库官方文档中关于xml.dom模块和xml.dom.minidom模块的内容。
Python处理XML之ElementTree篇
同样是上面那个ep1.xml文件,在此用ElementTree来构建和解析
构建ep1.xml
- from xml.etree.ElementTree import *
- def creat_element_with_text(upnode,tagname,nodetext):
- "创建一个元素节点,该节点只有一个文本子节点"
- #创建子节点并为其添加文本节点
- subnode = SubElement(upnode,tagname)
- subnode.text = nodetext
- return subnode
- #美化输出结果。elem为根节点,level缺省参数
- def beautify(elem, level=0):
- i = "\n" + level*" "
- if len(elem):
- if not elem.text or not elem.text.strip():
- elem.text = i + " "
- for e in elem:
- beautify(e, level+1)
- if not e.tail or not e.tail.strip():
- e.tail = i
- if level and (not elem.tail or not elem.tail.strip()):
- elem.tail = i
- return elem
- if __name__ == '__main__':
- #定义要构建的XML的文件的各种元素属性
- bookstore = [{'category':'COOKING', 'title':'Everyday Italian', 'language':'English', 'author':'Giada De Laurentiis', 'year':2005,'price':30.00},
- {'category':'JUVENILE', 'title':'Harry Potter', 'language':'English', 'author':'J K. Rowling', 'year':2005,'price':39.99},
- {'category':'WEB', 'title':'Learning XML', 'language':'English', 'author':'Erik T. Ray', 'year':2003,'price':39.95}]
- bookstoreNode = Element('bookstore')
- for book in bookstore:
- #构建book的元素及属性,注意year和price的文本节点要转换成字符串
- bookNode = SubElement(bookstoreNode,'book')
- bookNode.attrib['category'] = book['category']
- titleNode = creat_element_with_text(bookNode,'title',book['title'])
- titleNode.attrib['language'] = book['language']
- authorNode = creat_element_with_text(bookNode,'author',book['author'])
- yearNode = creat_element_with_text(bookNode,'year',str(book['year']))
- priceNode = creat_element_with_text(bookNode,'price',str(book['price']))
- tree = ElementTree(bookstoreNode)
- beautify(bookstoreNode)
- dump(tree)#用于输出该树
- #保存到ep1.xml文档中,编码方式是UTF-8
- tree.write('ep1.xml','UTF-8')
from xml.etree.ElementTree import *
def creat_element_with_text(upnode,tagname,nodetext):
"创建一个元素节点,该节点只有一个文本子节点"
#创建子节点并为其添加文本节点
subnode = SubElement(upnode,tagname)
subnode.text = nodetext
return subnode
#美化输出结果。elem为根节点,level缺省参数
def beautify(elem, level=0):
i = "\n" + level*" "
if len(elem):
if not elem.text or not elem.text.strip():
elem.text = i + " "
for e in elem:
beautify(e, level+1)
if not e.tail or not e.tail.strip():
e.tail = i
if level and (not elem.tail or not elem.tail.strip()):
elem.tail = i
return elem
if __name__ == '__main__':
#定义要构建的XML的文件的各种元素属性
bookstore = [{'category':'COOKING', 'title':'Everyday Italian', 'language':'English', 'author':'Giada De Laurentiis', 'year':2005,'price':30.00},
{'category':'JUVENILE', 'title':'Harry Potter', 'language':'English', 'author':'J K. Rowling', 'year':2005,'price':39.99},
{'category':'WEB', 'title':'Learning XML', 'language':'English', 'author':'Erik T. Ray', 'year':2003,'price':39.95}]
bookstoreNode = Element('bookstore')
for book in bookstore:
#构建book的元素及属性,注意year和price的文本节点要转换成字符串
bookNode = SubElement(bookstoreNode,'book')
bookNode.attrib['category'] = book['category']
titleNode = creat_element_with_text(bookNode,'title',book['title'])
titleNode.attrib['language'] = book['language']
authorNode = creat_element_with_text(bookNode,'author',book['author'])
yearNode = creat_element_with_text(bookNode,'year',str(book['year']))
priceNode = creat_element_with_text(bookNode,'price',str(book['price']))
tree = ElementTree(bookstoreNode)
beautify(bookstoreNode)
dump(tree)#用于输出该树
#保存到ep1.xml文档中,编码方式是UTF-8
tree.write('ep1.xml','UTF-8')
解析XML文档,在这里我是采用的大型XML文档解析法,因为项目的原因,XML文档必定非常的大,所以采用了这种方法。其实可以写的很简单的,各位看官可以自己去琢磨一下。
- from xml.etree.ElementTree import iterparse
- iparse = iterparse('ep6.xml',['start','end'])
- #查找顶层bookstore
- for event,elem in iparse:
- if event == 'start' and elem.tag == 'bookstore':
- Nodes = elem
- #print nodes
- break
- bookstore = [] #列表
- #获取所有book
- #以下三种方法都可以,但是我不知道后两种是否移除掉了不再使用的book
- books = (elem for event,elem in iparse if event == 'end' and elem.tag =='book')
- #books = Nodes.findall('book')
- #books = elem.findall('book')
- for i in books:
- book = {} #字典
- book['category'] = i.get('category')
- #print book['category']
- book['title'] = i.find('title').text.strip()
- #获取title元素的属性
- book['language'] = i.find('title').get('language')
- book['author'] = i.find('author').text.strip()
- book['year'] = i.find('year').text.strip()
- book['price'] = i.find('price').text.strip()
- bookstore.append(book)
- #print book
- #清除不再使用的book元素,减少内存使用
- Nodes.remove(i)
- print "bookstore:"
- i=1
- for book in bookstore:
- print 'book%s'%i
- #print book
- i=i+1
- for key in book:
- print ' %s : %s' % (key,book[key])
from xml.etree.ElementTree import iterparse
iparse = iterparse('ep6.xml',['start','end'])
#查找顶层bookstore
for event,elem in iparse:
if event == 'start' and elem.tag == 'bookstore':
Nodes = elem
#print nodes
break
bookstore = [] #列表
#获取所有book
#以下三种方法都可以,但是我不知道后两种是否移除掉了不再使用的book
books = (elem for event,elem in iparse if event == 'end' and elem.tag =='book')
#books = Nodes.findall('book')
#books = elem.findall('book')
for i in books:
book = {} #字典
book['category'] = i.get('category')
#print book['category']
book['title'] = i.find('title').text.strip()
#获取title元素的属性
book['language'] = i.find('title').get('language')
book['author'] = i.find('author').text.strip()
book['year'] = i.find('year').text.strip()
book['price'] = i.find('price').text.strip()
bookstore.append(book)
#print book
#清除不再使用的book元素,减少内存使用
Nodes.remove(i)
print "bookstore:"
i=1
for book in bookstore:
print 'book%s'%i
#print book
i=i+1
for key in book:
print ' %s : %s' % (key,book[key])
Python处理XML之SAX篇
(这一部分纯粹的转载,前面已经给了链接了)
前面介绍了python中使用DOM处理XML数据的方法,今天介绍另一个常用接口,SAX。
SAX是Simple API for XML的简称,最初由Java实现,最新版本是2.0,是一种事件驱动的API。SAX的基本思想如下:顺序读取XML文件内容,并在读取过程中根据读到的数据产生对应的事件,由用户编写的Handler决定如何响应事件。python的SAX2实现在xml.sax标准库模块中,下面以students.xml为例,演示SAX的基本用法。
students.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <students>
- <student id="1">
- <name>zhangsan</name>
- <age>20</age>
- <dob>1990.11.22</dob>
- </student>
- <student id="2">
- <name>lisi</name>
- <age>21</age>
- <dob>1992.06.15</dob>
- </student>
- </students>
<?xml version="1.0" encoding="UTF-8"?>
<students>
<student id="1">
<name>zhangsan</name>
<age>20</age>
<dob>1990.11.22</dob>
</student>
<student id="2">
<name>lisi</name>
<age>21</age>
<dob>1992.06.15</dob>
</student>
</students>
sax_demo.py
- # -*- coding:utf-8 -*-
- from xml.sax import handler,parseString
- classMyGeneralHandler(handler.ContentHandler):
- """ 自定义事件处理器 """
- def startDocument(self):
- print 'Document Start...'
- def endDocument(self):
- print 'Document End...'
- def startElement(self, name, attrs):
- print 'encounter element(%s)' % (name)
- def endElement(self, name):
- print 'leave element(%s)' % (name)
- def characters(self, content):
- print 'characters:' + content
- xml_file = open('students.xml','r')
- parseString(xml_file.read(), #xml数据内容
- MyGeneralHandler()) # 事件处理对象
- xml_file.close()
# -*- coding:utf-8 -*-
from xml.sax import handler,parseString
classMyGeneralHandler(handler.ContentHandler):
""" 自定义事件处理器 """
def startDocument(self):
print 'Document Start...'
def endDocument(self):
print 'Document End...'
def startElement(self, name, attrs):
print 'encounter element(%s)' % (name)
def endElement(self, name):
print 'leave element(%s)' % (name)
def characters(self, content):
print 'characters:' + content
xml_file = open('students.xml','r')
parseString(xml_file.read(), #xml数据内容
MyGeneralHandler()) # 事件处理对象
xml_file.close()
sax_demo.py的运行结果:
- Document Start...
- encounter element(students)
- characters:
- characters:
- encounter element(student)
- characters:
- characters:
- characters:
- encounter element(name)
- characters:zhangsan
- leave element(name)
- characters:
- characters:
- encounter element(age)
- characters:20
- leave element(age)
- characters:
- characters:
- encounter element(dob)
- characters:1990.11.22
- leave element(dob)
- characters:
- characters:
- leave element(student)
- characters:
- characters:
- characters:
- encounter element(student)
- characters:
- characters:
- encounter element(name)
- characters:lisi
- leave element(name)
- characters:
- characters:
- encounter element(age)
- characters:21
- leave element(age)
- characters:
- characters:
- encounter element(dob)
- characters:1992.06.15
- leave element(dob)
- characters:
- characters:
- leave element(student)
- characters:
- characters:
- leave element(students)
- Document End...
Document Start...
encounter element(students)
characters:
characters:
encounter element(student)
characters:
characters:
characters:
encounter element(name)
characters:zhangsan
leave element(name)
characters:
characters:
encounter element(age)
characters:20
leave element(age)
characters:
characters:
encounter element(dob)
characters:1990.11.22
leave element(dob)
characters:
characters:
leave element(student)
characters:
characters:
characters:
encounter element(student)
characters:
characters:
encounter element(name)
characters:lisi
leave element(name)
characters:
characters:
encounter element(age)
characters:21
leave element(age)
characters:
characters:
encounter element(dob)
characters:1992.06.15
leave element(dob)
characters:
characters:
leave element(student)
characters:
characters:
leave element(students)
Document End...
从上面的例子可以看出,使用SAX最主要的工作就是编写事件处理类,在该类中决定处理哪些元素和文本。从编程者的角度看,SAX并没有DOM来的直观和方便,DOM可以任意操作文档的任意节点,而在编写SAX的handler时,你需要时刻记住当前解析的节点(见下面的例子)。另外,SAX的事件驱动模型有一个天生的缺陷,就是只能读XML,不能修改!那我们为什么还要用SAX呢?与DOM相比,SAX的优点是:
不需要把整篇XML文档读入内存,在XML文件非常大时,一般使用SAX。
如果文档只需解析一次,使用SAX更有效。
使用SAX可以为XML创建任意的数据结构,而不用非得使用DOM。实际上,SAX与DOM并不是完全互斥等价,基于DOM的解析器在创建DOM树的过程中也可能使用SAX来获取数据,SAX是读取XML数据的一种方式,DOM则是W3C的一套标准。
下面来看一个更有意义的例子,利用SAX来读取刚才的students.xml并创建python中的student字典对象。
- # -*- coding:utf-8 -*-
- from xml.sax import handler, parseString
- class StudentsHandler(handler.ContentHandler):
- def __init__(self, students):
- self.students = students
- # 记录解析过程中上一次遇到的元素名
- self.temp_name = ''
- def startElement(self, name, attrs):
- if name == 'students':
- pass
- elif name == 'student':
- student = {}
- for (attr_name, attr_value) in attrs.items():
- # 将id属性作为student对象的属性
- student[attr_name] = attr_value
- self.students.append(student)
- else:
- self.temp_name = name
- def characters(self, content):
- if self.temp_name:
- # temp_name不为空表示刚遇到元素节点的开始标签,那么content就是该元素节点中的文本
- # 由于SAX是从上到下解析XML的,那么该属性应该是最后加入到students列表中的student对象的属性
- self.students[-1][self.temp_name] = content
- self.temp_name = ''
- students = []
- xml_file = open('students.xml', 'r')
- parseString(xml_file.read(), StudentsHandler(students))
- xml_file.close()
# -*- coding:utf-8 -*-
from xml.sax import handler, parseString
class StudentsHandler(handler.ContentHandler):
def __init__(self, students):
self.students = students
# 记录解析过程中上一次遇到的元素名
self.temp_name = ''
def startElement(self, name, attrs):
if name == 'students':
pass
elif name == 'student':
student = {}
for (attr_name, attr_value) in attrs.items():
# 将id属性作为student对象的属性
student[attr_name] = attr_value
self.students.append(student)
else:
self.temp_name = name
def characters(self, content):
if self.temp_name:
# temp_name不为空表示刚遇到元素节点的开始标签,那么content就是该元素节点中的文本
# 由于SAX是从上到下解析XML的,那么该属性应该是最后加入到students列表中的student对象的属性
self.students[-1][self.temp_name] = content
self.temp_name = ''
students = []
xml_file = open('students.xml', 'r')
parseString(xml_file.read(), StudentsHandler(students))
xml_file.close()
最后总结一下SAX的常用场合:
1.处理大型XML文件
2.只需要文件中的部分内容,或者只需从XML中获取特定信息
3.比较高级的话题,想要建立自己的XML数据模型。
转载:http://blog.youkuaiyun.com/wanghuiqi2008/article/details/8074302