前回まではDOMを使っていたが、今回からはSAX(Simple API for XML)を使ってXMLを扱ってみる。DOMと違ってメモリ上にXMLファイルの情報を全て読み込むようなことはなく、順次読み込みを行い、読み込んだ内容に対して逐次イベントを発生させる仕組みのAPIである。
Wikipedia : Simple API for XML
XML文書をツリー構造として扱うDOMと異なり、一連のイベントとして表現するイベント駆動型のAPIである。したがって、アプリケーションが積極的にAPIにアクセスするDOMに対し、SAXではアプリケーションがイベントが来るのを待ち受ける受動的な動作が大部分を占める。
あるXMLを扱うアプリケーションを作成する際、DOMを使うかSAXを使うかは、両者のメリットデメリットをしっかり認識した上で扱うべきであるが、一般的に大きなサイズのXMLファイルであればSAXを用いた方が良さそうだ。
—–
上述したようにSAXではXMLファイルを読む込む際の色々な状況がイベントとして規定されており、そのイベントに対応した関数がクラスとして(Java等ではInterfaceとして)用意されているので、そのクラスを継承し、関数の内容を実装したクラスを作成、登録することにより、ある特定のXMLファイルを扱うアプリケーションを作成することが出来る。以下で簡単にXMLファイルの内容を表示するクラスSimpleHandlerを作成し、実際に表示してみる。
import sys from xml.sax import ContentHandler from xml.sax import make_parser class SimpleHandler(ContentHandler): def startDocument(self): print "DOCUMENT START" def endDocument(self): print "DOCUMENT END" def startElement(self, name, attrs): print "Start of <", name, ">" for key in attrs.keys(): print key, "=", attrs[key] def endElement(self, name): print "End of <", name, ">" if __name__ == "__main__": handler = SimpleHandler() parser = make_parser() xmlFile = open(sys.argv[1], 'r') parser.setContentHandler(handler) parser.parse(xmlFile)
Pythonにて用意されているContentHandlerクラスを継承し、startDocument、endDocument、startElement、endElementの四つの関数をoverrideした形となっている。それぞれの関数は、ただプリントするだけの簡単なもの。startElement関数内ではXMLファイル内のタグの属性も出力するようにしてみた。
このプログラムで以下のXMLファイルを読み込んでみたときの実行結果を見てみる。
<?xml version="1.0"?> <os> <windows company="microsoft" price="not free"> </windows> <unix> </unix> <linux price="free"> <debian/> <fedora/> <redhat/> </linux> <macos company="apple"> </macos> </os>
実行結果。
DOCUMENT START Start of < os > Start of < windows > company = microsoft price = not free End of < windows > Start of < unix > End of < unix > Start of < linux > price = free Start of < debian > End of < debian > Start of < fedora > End of < fedora > Start of < redhat > End of < redhat > End of < linux > Start of < macos > company = apple End of < macos > End of < os > DOCUMENT END
ドキュメントが読み込まれた段階でstartDocumentが、タグ(
またSAXではXMLファイルの内容そのものを扱うContentHandlerの他に、読み込みエラー時に読み込まれるErrorHandlerや、DTD使用時の為のDTDHandler、EntityResolverといったクラスも用意されている。ErrorHandlerはおそらく実装はほぼ必須だと思われ、用意されているwarning、error、fatalErrorという関数に、そのアプリケーションで求められるエラー処理を記述することにより扱う。ErrorHandlerをparserに登録する際は、
class SimpleErrorHandler(ErrorHandler): def warning(self, exception): print "Warning!" def error(self, exception): print "Error!!" def fatalError(self, exception): print "Fatal Error!!!" errHandler = SimpleErrorHandler() parser = make_parser() parser.setErrorHandler(errHandler)
のように登録すれば良い。