XML和JSON是两个重要的网络数据交换标准。
1. XML (eXtensible Markup language, 可扩展标记语言)
以下是书中附带的一个XML示例文档。
Dr. No
1962
1.1M
59.5M
Live and Let Die
1973
7M
126.4M
Skyfall
2012
175M
1108.6M
XML是纯文本格式,XML有一套语法规则和关机元素,一个XML文档永远 以声明XML文档的一行代码开头。
XML文件必须有且仅有一个根元素,它包裹整个文档,如例子里的根元素
一个XML元素包括标签和内容,标签包括起始标签和终止标签,起始标签中和可以包含属性,属性和内容一样可以用来存放数据(信息),XML的属性值必须加引号 ;起始标签也可以用一个/,自己闭合,即不用终止标签;XML可以自己选择元素的名字,只要符合命名规则就可以(不能以数字或xml开头 、不能包括空格、区分大小写);内容中遇到特殊字符,须使用预先定义的转义字符串来代替,但如果数据中需要转义的字符太多时 ,可放到 部件中,这样就不会被解析。。
一个XML文件是一个有层次的树形结构,元素里还可以包含其它元素;元素可以嵌套,但必须是严格嵌套,不允许交叉嵌套。
XML文档结构可以由用户自定义(标签名和层次结构的深度),用户可用文档类型定义(DTD)来描述;由于XML是可自定义的,就可能存在同样的元素名用于表达不同内容的情况,处理这种情况需要用到命名空间技术。
2. Python 解析XML文件
1) DOM
定义一个类Movie存放电影信息,与例子中xml文件相对应。用xml.dom.minidom对文档进行解析,用到的方法包括:parse、hasChildNodes、getAttribute、getElementsBuTagName和data属性。需要注意的是要用nodeType==Node.ELEMENT_NODE进行判断过滤掉Text node。
class Movie(object):
def __init__(self, id=None, name=None, year=None, actors=None, budget=None, boxoffice=None):
self.__id__ = id
self.__name__ = name
self.__year__ = year
self.__actors__ = actors
self.__budget__ = budget
self.__boxoffice__ = boxoffice
def get_id(self):
return self.__id__
def get_name(self):
return self.__name__
def get_year(self):
return self.__year__
def get_actors(self):
return self.__actors__
def get_budget(self):
return self.__budget__
def get_boxoffice(self):
return self.__boxoffice__
def to_txt(self,separator=','):
bond = self.__actors__['bond']
villain = self.__actors__['villain']
line = str(self.__id__) + separator + \
self.__name__ + separator + \
str(self.__year__) + separator + \
self.__budget__ + separator + \
self.__boxoffice__ + separator + \
bond + separator + villain
return line
from xml.dom import minidom as mdom
from xml.dom.minidom import Node
def get_movies_by_dom(xmlfile):
movies = []
doc = mdom.parse(xmlfile)
root = None
if doc.hasChildNodes():
root = doc.childNodes[0]
else:
return movies
for mve in root.childNodes:
if mve.nodeType == Node.ELEMENT_NODE:
id = mve.getAttribute('id')
node = mve.getElementsByTagName("name")
name = node[0].childNodes[0].data
node = mve.getElementsByTagName("year")
year = node[0].childNodes[0].data
node = mve.getElementsByTagName("actors")
bond = node[0].getAttribute('bond')
villain = node[0].getAttribute('villain')
actors = {'bond':bond, 'villain':villain}
node = mve.getElementsByTagName("budget")
budget = node[0].childNodes[0].data
node = mve.getElementsByTagName("boxoffice")
boxoffice = node[0].childNodes[0].data
mv = Movie(id, name, year, actors, budget, boxoffice)
movies.append(mv)
return movies
if __name__ == '__main__':
movies = get_movies_by_dom('bond.xml')
for mv in movies:
print mv.to_txt()
2)SAX
dom解析xml是将整个文档树加载到内存中,因此在解析大文件时需要考虑使用sax进行解析。需要引入xml.sax中的parse函数和xml.sax.handler中的ContentHandler。MyContentHandler继承ContentHandler,定义__movies__(列表)、__movie__和__tag_name__三个属性,记录解析过程的状态信息。当startElemet的节点标签名为movie时创建一个movie对象,当endElemet的节点标签名为movie时,表示
# -*- coding:utf-8 -*-
class Movie(object):
def __init__(self, id=None, name=None, year=None, actors=None, budget=None, boxoffice=None):
self.__id__ = id
self.__name__ = name
self.__year__ = year
self.__actors__ = actors
self.__budget__ = budget
self.__boxoffice__ = boxoffice
def get_id(self):
return self.__id__
def get_name(self):
return self.__name__
def get_year(self):
return self.__year__
def get_actors(self):
return self.__actors__
def get_budget(self):
return self.__budget__
def get_boxoffice(self):
return self.__boxoffice__
def set_id(self, id):
self.__id__ = id
def set_name(self, name):
self.__name__ = name
def set_year(self, year):
self.__year__ = year
def set_actors(self, actors):
self.__actors__ = actors
def set_budget(self, budget):
self.__budget__ = budget
def set_boxoffice(self, boxoffice):
self.__boxoffice__ = boxoffice
def to_txt(self,separator=','):
bond = self.__actors__['bond']
villain = self.__actors__['villain']
line = str(self.__id__) + separator + \
self.__name__ + separator + \
str(self.__year__) + separator + \
self.__budget__ + separator + \
self.__boxoffice__ + separator + \
bond + separator + villain
return line
from xml import sax
from xml.sax.handler import ContentHandler
class MovieContentHandler(ContentHandler):
def __init__(self):
ContentHandler.__init__(self)
self.__movies__ = []
self.__movie__ = None
self.__tag_name__ = None
def get_movies(self):
return self.__movies__
def startDocument(self):
self.__movies__ = []
def endDocument(self):
pass
def startElement(self, name, attrs):
if name == 'movie':
self.__movie__ = Movie()
self.__movie__.set_id(attrs['id'])
elif name == 'actors':
self.__movie__.set_actors({'bond': attrs['bond'], 'villain': attrs['villain']})
self.__tag_name__ = name
def endElement(self, name):
if name == 'movie':
self.__movies__.append(self.__movie__)
self.__movie__ = None
self.__tag_name__ = ''
def characters(self, content):
if self.__tag_name__ == 'name':
self.__movie__.set_name(content)
elif self.__tag_name__ == 'year':
self.__movie__.set_year(content)
elif self.__tag_name__ == 'budget':
self.__movie__.set_budget(content)
elif self.__tag_name__ == 'boxoffice':
self.__movie__.set_boxoffice(content)
if __name__ == '__main__':
mh = MovieContentHandler()
sax.parse('bond.xml', mh)
movies = mh.get_movies()
for movie in movies:
print movie.to_txt()
3)ElementTree
import xml.etree.ElementTree as ET
def get_moives_by_et(xmlfile):
movies = []
doc = ET.parse(xmlfile)
root = doc.getroot()
for child in root:
id = child.attrib['id']
name = child.find('name').text
year = child.find('year').text
actors = child.find('actors').attrib
budget = child.find('budget').text
boxoffice = child.find('boxoffice').text
movie = Movie(id, name, year, actors, budget, boxoffice)
movies.append(movie)
return movies
if __name__ == '__main__':
movies = get_moives_by_et('bond.xml')
for movie in movies:
print movie.to_txt()
3. JSON
JSON是一种源于JavaScript编程语言的数据格式,数据保持在键值对(Key/Value pair)里,键和值用冒号(:)隔开,键值对用逗号(,)隔开,不同类型的括号(大括号和方括号)能够描述层级结构。如果用Python的数据结构来描述的话,大括号({})对应字典,中括号([])对应列表。相比与XML,JSON不能添加注释、不能区分缺失的值和空值、没有命名空间、没有DTD。JSON是一种通用的数据交换标准。JSON在python 操作比较简单,掌握load、loads、dump和dumps几个方法就够用了,要注意的是ensuer_ascii 参数的使用。
import json
if __name__ == '__main__':
f = open('indy.json')
data = json.load(f)
print json.dumps(data, ensure_ascii=False,)
f.close()