PythonとSAXでXMLを扱う
XMLを扱いたくなったのでメモメモ。
XMLを扱うためのAPIとして、DOM(Document Object Model)を構築する方法と、SAX(Simple API for XML)ってのを使う方法がある。
どちらもW3Cで標準化されているAPIだから、Pythonに限らず、いろんな言語で同じようにXMLを扱うことができる。
HTML上のJavaScriptなんかを触ってると、DOMはよく出てくるね。
DOMとSAXの違いは、DOMはメモリ上にXMLのデータを全部取り込んでから処理をするのに対して、SAXはデータを読み込んだら逐次処理していく点。
DOMは、XMLの構造をツリー構造として扱うことができるから、いろいろ高度なことができる。
ただ、メモリ上に全てのデータを展開するから、メモリを食うし、重い。
SAXは、XMLのタグの出現を「イベント」として扱うAPI。
読み込んだデータをメモリ上にとっておかないから、非常に軽い。
ただし、後からXMLの構造をいじったりするのは苦手。
今回扱いたいデータはWikipediaのダンプデータ(Wikipedia:データベースダウンロード - Wikipedia)。
pages-articles.xml.bz2を解凍すると6GB程度になる。これを全部メモリ上に読み込むのは大変なので、SAXを使って見ることにする。
基本は以下のソース
import xml.sax import xml.sax.handler import sys class Handler(xml.sax.handler.ContentHandler): def startElement(self, name, attrs): print "Start: " + name def endElement(self, name): print "End: " + name def characters(self, content): print "character:" + content return def main(): parser = xml.sax.make_parser() parser.setContentHandler(Handler()) parser.parse(sys.stdin) return if __name__=="__main__": main()
Handlerのメソッドとして、開始タグを見つけた場合、終了タグを見つけた場合、その他の文字を見つけた場合の処理を書いておく。
nameにタグ名、attrsに属性(辞書と同じように扱える)が入っているので適宜処理。
XMLには名前空間の考え方があって、あるXMLデータに別のXMLデータを埋め込むことが簡単にできる。
(例えば、HTML文章にSVG文章を埋め込んだり、SVG文章やXHTML文章にクリエーティブコモンズのライセンスをXML形式で埋め込むとか)
import xml.sax import xml.sax.handler import sys class Handler(xml.sax.handler.ContentHandler): def startElementNS(self, name, qname, attrs): print "Start:", name, qname def endElementNS(self, name, qname): print "End:", name, qname def characters(self, content): print "character:" + content return def main(): parser = xml.sax.make_parser() parser.setContentHandler(Handler()) parser.setFeature(xml.sax.handler.feature_namespaces, True) parser.parse(sys.stdin) return if __name__=="__main__": main()
こうすると、nameが(名前空間,タグ名)という形式になる。attrのキーも(名前空間,属性名)になる。
shogo82148/svg2css @ GitHubを作るのにもSAXを使用中。はじめは「簡単な置換だからSAXでいけるだろー」ってSAXで作ったら、参照が必要になって、結局DOMっぽい物を作っているというね・・・。