一、DOM vs SAX
操作XML有两种方法:DOM和SAX。DOM会把整个XML读入内存,解析为树,因此占用内存大,解析慢,优点是可以任意遍历树的节点。SAX是流模式,边读边解析,占用内存小,解析快,缺点是我们需要自己处理事件。
优先考虑SAX,因为DOM实在太占内存
二、使用SAX解析XML
需准备好这3个函数:start_element,end_element和char_data,就可开始解析XML。
举例,当SAX解析器读到一个节点时:
<a href="/">python</a>
产生三个事件:
1、start_element事件,在读取<a href="/">时;
2、char_data事件,在读取python时;
3、end_element事件,在读取</a>时。
解析一段xml的代码:
from xml.parsers.expat import ParserCreate
class DefaultSaxHandler(object):
def start_element(self, name, attrs):
print('sax:start_element: %s, attrs: %s' % (name, str(attrs)))
def end_element(self, name):
print('sax:end_element: %s' % name)
def char_data(self, text):
print('sax:char_data: %s' % text)
xml = r'''<?xml version="1.0"?>
<ol>
<li><a href="/python">Python</a></li>
<li><a href="/ruby">Ruby</a></li>
</ol>
'''
handler = DefaultSaxHandler()
parser = ParserCreate()
parser.StartElementHandler = handler.start_element
parser.EndElementHandler = handler.end_element
parser.CharacterDataHandler = handler.char_data
parser.Parse(xml)
直接解析xml的步骤:
1、准备一段xml的代码,待解析
xml = r'''<?xml version="1.0"?>
<ol>
<li><a href="/python">Python</a></li>
<li><a href="/ruby">Ruby</a></li>
</ol>
'''
2、定义DefaultSaxHandler类,类中定义三个方法分别用于解析标签开头、标签内内容、标签结尾
class DefaultSaxHandler(object)
def start_element(self, name, attrs):
print('sax:start_element: %s, attrs: %s' % (name, str(attrs)))
def end_element(self, name)
print('sax:start_element: %s, attrs: %s' % (name, str(attrs)))
def char_data(self, text):
print('sax:char_data: %s' % text)
3、使用DefaultSaxHandler( )创建DefaultSaxHander ( )
handler=DefaultSaxHandler( ) # 创建DefaultSaxHandler()对象
4、使用ParserCreate( )创建xml解析器
parser=ParserCreate( ) #创建 XML 解析器。该函数建立一个新的 XML 解析器并返回可被其它 XML 函数使用的资源句柄
5、分别调用handler的三个方法,并将返回值赋给对应的parser.ElementHandler
parser.StartElementHandler=handler.start_element #调用handler的start_element方法,并将返回值赋给parser.StartElementHandler
parser.EndElementHandler=handler.end_element #调用handler的end_element方法,并将返回值赋给EndElementHandler
parser.CharacterDataHandler=handler.char_data #调用handler的char_data方法,并将返回值赋给CharacterDataHandler
6、最后调用parse()传入xml参数,从而进行解析
parser.Parse(xml)
运行:
三、生成xml
除了解析XML外,如何生成XML呢?99%的情况下需要生成的XML结构都是非常简单的,因此,最简单也是最有效的生成XML的方法是拼接字符串:
L = []
L.append(r'<?xml version="1.0"?>')
L.append(r'<root>')
L.append(encode('some & data'))
L.append(r'</root>')
return ''.join(L)
join()函数的用法 :https://www.cnblogs.com/jsplyy/p/5634640.html
如果要生成复杂的XML呢?建议你不要用XML,改成JSON。附:JSON与XML的区别比较 https://www.cnblogs.com/lsohvaen001/p/7887502.html
总结:解析XML时,注意找出自己感兴趣的节点,响应事件时,把节点数据保存起来。解析完毕后,就可以处理数据。
四、练习
题目:
代码 :
from xml.parsers.expat import ParserCreate
from urllib import request
parse_dict = {}
class DefaultSaxHandler(object):
def start_element(self, name, attrs):
if name == 'yweather:location':
parse_dict['city'] = attrs['city']
def parseXml(xml_str):
print(xml_str + '\n')
handler = DefaultSaxHandler()
parser = ParserCreate()
parser.StartElementHandler = handler.start_element
parser.Parse(xml_str)
return parse_dict
# 测试:
URL = 'https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20%3D%202151330&format=xml'
with request.urlopen(URL, timeout=4) as f:
data = f.read()
result = parseXml(data.decode('utf-8'))
assert result['city'] == 'Beijing'
print('ok')
运行:
解析url所指向内容的步骤:
1、准备一个url
URL = 'https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20%3D%202151330&format=xml'
2、打开并读入url内容
with request.urlopen(URL, timeout=4) as f:
data = f.read()
3、定义DefaultSaxHandler类,设置响应事件,注意找出自己感兴趣的节点,把节点数据保存起来
class DefaultSaxHandler(object): #定义DefaultSaxHandler类
def start_element(self, name, attrs): #设置响应事件
if name == 'yweather:location': #自己感兴趣的节点
parse_dict['city'] = attrs['city'] #把节点数据(即yweather:location标签的city属性值)保存到全局变量parse_dict的city值
4、定义函数 parseXml用于解析xml文件
def parseXml(xml_str):
print(xml_str + '\n')
handler = DefaultSaxHandler() #创建DefaultSaxHandler对象handler
parser = ParserCreate() #创建解析器
parser.StartElementHandler = handler.start_element #调用start_element方法,爆粗将节点数据
parser.Parse(xml_str) 解析url的内容xml_str
return parse_dict 返回保存了节点数据的全局变量parse_dict
5、调用函数parseXml()进行解析xml内容
result = parseXml(data.decode('utf-8')) #将返回值赋给result
assert result['city'] == 'Beijing' #使用断言看result的city属性值是否为'beijing'
print('ok') #运行完毕打印ok