Python の何が気に入っているのかというはなし 〜SAX の場合〜

端的に言うとライブラリの「センス」がいいのです。細かい気配りの効いたお店ってあるでしょう。あんな感じ。

今日ちょっと話したんですが、最近大変気に入った Python の SAX のはなし。たいていの OO 言語の SAX 実装は Visitor パターンで、startElement や endElement などのメンバをもったオブジェクトと XML の実データを渡してパースしてやることになると思います。Python の場合 ContentHandler クラスの子クラスを作ることになります。ここまではふつう。

ふと、saxutils パッケージに XMLGenerator クラスなる、ContentHandler のサブクラスがあります。説明を読むと、そのまま出力されるだけだったり、クラス名も最初謎でした。これ何に使うんだ? ここで気づくのです! あぁ、これまさに Generator じゃん!!

from xml.sax.saxutils import XMLGenerator

gen = XMLGenerator()

gen.startDocument()
gen.startElement('html', {})
gen.startElement('head', {})
gen.endElement('head')
gen.startElement('body', {})
gen.startElement('a', {'href': 'http://d.hatena.ne.jp/u-no/'})
gen.characters('>>diary<<')
gen.endElement('a')
gen.endElement('body')
gen.endElement('html')
gen.endDocument()

わかりますか? startElement などの、本来 Parser ライブラリから呼ばれるメンバ関数を、ユーザーのプログラムから呼ぶんです。出力はこんな感じ。

<?xml version="1.0" encoding="iso-8859-1"?>
<html><head></head><body><a href="http://d.hatena.ne.jp/u-no/">&gt;&gt;diary&lt;&lt;</a></body></html>

私はこのとき、DOM ツリーを作らずに、XML エスケープをしながら出力する XMLWriter クラスのようなモノを探していました。それがまさか Parser のパッケージにあるとは! Parser 用インターフェースを逆に使うと Generator になるよという指摘。1本とられた感じです。

さらに関心したのは、startElement の第2引数。SAX からは Attributes なるクラスのオブジェクトがとんでくるらしいんですが、よく見てください。辞書型とインターフェースが酷似している。そして、XMLGenerator 内では辞書型と共通のメンバ関数しか使ってないようで、そのため上記のように第2引数に辞書型を渡せるんですね。明らかに上記のような使い方を意識しています。

ライブラリの善し悪しって、どういう使われ方をするか想定できるかに依ると思うのですよ。この例なんかは本当に気配りがきいていて、Python ではこういう「上品な」仕組みによく出くわします。そこがいいんですね。

# そういえば、これでさらに閉じタグとの対応を validate してくれれば良かったんだけどな。まぁ、ラッパーでも作ればいいんですけど