XML和JSON是两个重要的网络数据交换标准。
1. XML (eXtensible Markup language, 可扩展标记语言)
以下是书中附带的一个XML示例文档。
<?xml version="1.0" encoding="ISO-8859-1"?> <bond_movies> <movie id="1"> <name>Dr. No</name> <year>1962</year> <actors bond="Sean Connery" villain="Joseph Wiseman"/> <budget>1.1M</budget> <boxoffice>59.5M</boxoffice> </movie> <movie id="2"> <name>Live and Let Die</name> <year>1973</year> <actors bond="Roger Moore" villain="Yaphet Kotto"/> <budget>7M</budget> <boxoffice>126.4M</boxoffice> </movie> <movie id="3"> <name>Skyfall</name> <year>2012</year> <actors bond="Daniel Craig" villain="Javier Bardem"/> <budget>175M</budget> <boxoffice>1108.6M</boxoffice> </movie> </bond_movies>XML是纯文本格式,XML有一套语法规则和关机元素,一个XML文档永远 以声明XML文档的一行代码开头。
XML文件必须有且仅有一个根元素,它包裹整个文档,如例子里的根元素<bond_movies> </bond_movies>。
一个XML元素包括标签和内容,标签包括起始标签和终止标签,起始标签中和可以包含属性,属性和内容一样可以用来存放数据(信息),XML的属性值必须加引号 ;起始标签也可以用一个/,自己闭合,即不用终止标签;XML可以自己选择元素的名字,只要符合命名规则就可以(不能以数字或xml开头 、不能包括空格、区分大小写);内容中遇到特殊字符,须使用预先定义的转义字符串来代替,但如果数据中需要转义的字符太多时 ,可放到<! [CDATA[ ]] > 部件中,这样就不会被解析。。
一个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时,表示<movie>...</movie>完成了,将__movie__添加到__movies__列表。
# -*- 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()
