argius note

プログラミング関連

XMLを扱うAPIの復習

まず始めに、なぜXMLの復習をするのかを述べておきたいと思います。
次のような機能要件があります。

あるデータファイルがXMLで書かれています。構造は言わばCSVと同じで、1つ以上の要素を持った行が連続しているものです。サイズが大きいので、メモリを節約するため、行単位で読み込んで使ったらすぐに破棄させます。読み込むタイミングは、呼び出し側で任意に行えるようにします。

さて、Javaの標準APIでは、1.4のときにDOMとSAXがサポートされています。
DOMは、パーサがXML全体を木構造に読み込んでから操作を行います。そのため、文書全体がメモリ上に展開されます。この仕組みでは、ランダムアクセスや構造の変更が容易となりますが、文書が大きいとメモリを逼迫してしまいます。
SAXは、パーサが要素にたどりつくごとにイベント通知を行い、使用者側はそれを受け取るごとに操作を行います。ここで言うイベントとは、非同期のイベントではなく、コールバックすることを言っています。この仕組みでは、データを保持するかどうかは使用者に委ねられます。
この2つのAPIを使って、冒頭の仕様を満たせるでしょうか。
まずDOMは、メモリ不足になるのは明らかですし、「メモリを節約する」という問題が解決できません。そもそもDOMは、メモリ上で扱う構造をXMLで扱うためのものなのでしょう。
SAXは、メモリを節約することは使用者次第で制御できますが、呼び出すきっかけを制御するのが困難です。SAXは、解析の詳細をイベントハンドラに任せることはできますが、途中まで解析するような処理はできません。
こういったケースでは、DOMとSAXでは難しいようです。SAXのように、パーサが使用者にデータを渡すタイプをpush型と呼ぶようです。今回はこれとは反対に、使用者がデータを取りに行くようにしたいのです。これをpull型と呼ぶそうです。このpull型のAPIを使えば、例えばBufferedReaderを使ったテキストファイル操作のような感覚で、要素を取り出すことができるようになります。

// 想像上のAPI
XmlReader reader = factory.getReader();
while (reader.hasNext()) {
    // Element1つ分だけ読み込む
    Element element = reader.next();
}

残念ながら、Java1.4の時点では、標準APIでは未サポートです。サードパーティによるAPIはいくつか発表されているようです。そして、標準APIでは、Java6でStAX(Streaming API for XML)というAPIが追加されています。

参考:Streaming API for XML - Wikipedia