PythonでXMLを扱う(5)

前回までは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が、タグ()が読み込まれた段階でstartElementが呼び出されている様子が分かると思う。同様にendDocument、endElementもそれぞれ終わりが読み込まれたときに呼び出されているのが分かると思う。このようにSAXでは用意された「イベントに対応した関数」を実装することにより使用する。ContentHandlerの関数の一覧はこちらで確認できる。
また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)

のように登録すれば良い。