一日以上の長

JavaはJ2SE6から(正確にはJava Web Services Developer Packから)XML用のAPIとしてStAXと呼ばれる新しいパーサ(プルパーサ)を提供したが、これはC#で既に実装されている同様のパーサと非常に良く似たものである。

以下はプルパーサを使ってhoge.xmlを読み込む簡易コードだが、とてもよく似ているのが解るだろう。

XmlReader reader = XmlReader.Createnew FileStream("hoge.xml", FileMode.Open, FileAccess.Read));
while (reader.Read())
{
    if (reader.IsStartElement())
    {
        if (reader.LocalName.Equals("hoge"))
        {
            hogeエレメントに対する処理
        }
    }
}
reader.Close();
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLStreamReader reader = factory.createXMLStreamReader(new FileStream("hoge.xml"));
for (; reader.hasNext(); reader.next()) {
    if (reader.getEventType() == XMLStreamConstants.START_ELEMENT)  {
        if (reader.getLocalName().equals("hoge"))  {
            hogeエレメントに対する処理
        }
    }
}
reader.close();

リーダオブジェクトの属性を設定する場合も同様で、C#ではXmlReaderSettingsオブジェクトを使い、Javaの場合はfactoryの属性として設定する。

XmlReaderSettings settings = new XmlReaderSettings();
settings.ProhibitDtd = false;
settings.ValidationType = ValidationType.DTD;
settings.XmlResolver = new HogeResolver();
XMLInputFactory factory = XMLInputFactory.newInstance();
factory.setProperty(XMLInputFactory.IS_VALIDATING, true);
factory.setProperty(XMLInputFactory.SUPPORT_DTD, true);
factory.setProperty(XMLInputFactory.RESOLVER, new HogeResolver());

と、このように使い方も酷似しているのでC#->

XmlReader reader = XmlReader.Createnew FileStream("hoge.xml", FileMode.Open, FileAccess.Read));
while (reader.Read())
{
    if (reader.IsStartElement())
    {
        if (reader.LocalName.Equals("hoge"))
        {
            //hoge要素を基点としたツリーを処理するためのリーダを作れる
            XmlReader subReader = reader.ReadSubtree();
            while (subReader.Read())
            {
                hoge要素内を走査するのに特化した処理を書ける
            }
        }
    }
}

通常、プルパーサは先頭の要素から順に取り出すことしかできないので、このように任意の要素内だけを走査するAPIがあると、ネストした要素の処理や再帰を書くのがとても楽になるのだ。
対してJavaは上記のようなカーソルAPIの他に、XML要素に対応して発生するイベントを補足しながら処理するためのAPI(XMLEventReader)も用意されているが、できればC#同様にサブツリーを処理するAPIが欲しかった。この辺は最初からプルパーサに拘ってきた.NETに一日の長があるように感じる。