StAX - XmlParser

Java6から加わった標準XMLパーサにStAXというパーサーがあります。JavaXMLパーサーといえば、SAXとDOMが有名ですが、StAXは第3のパーサーでSAX寄りの性質を持ちます。
DOMはXMLをパースした上で構造化した文書モデル(Document Object Model=DOM)へ変換をかけるAPIです。小粒なXMLであれば良いのですが、巨大なXMLの場合などどうしてもパフォーマンス面やリソース面が気になってしまいます。その代わりに非常に解り易いのですが。
逆にSAXは頭から読込み、タグの始まりや終わりなど、特定のタイミングでイベントが発生するタイプのAPIです。DOMに比べればパフォーマンス面もリソース面も優秀なのですが、今どのような状況でそのイベントが発生しているか?などの把握は実装者に委ねられるため、作りこむのに手間がかかります。
StAXはSAXの流れを組むAPIですが、イベントの発生や種別を解り易く書き換えている、と考えれば良いでしょう。

XMLStreamReaderとXMLEventReader

StAXではXMLStreamReaderとXMLEventReaderの2つのリーダが使用できます。内部的な動きはほとんど同じなのですが、EventReaderの方はイベントをEventオブジェクトとして扱える為、オブジェクト指向っぽくコーディングできるのが特徴です。一方、XMLStreamReaderでは発生するイベントは同じなのですが、イベントステータスを返すだけで、実際のタグやテキストはReaderから取得する感じになります。どちらでも大差はないですが、大きなパーサを構築するならばわかりやすいEventReader、速度重視だったりコンパクトなパーサであればXMLStreamReaderで良いのではないでしょうか?
実際にReaderを作成するには次のようにコードを書きます。

XMLInputFactory factory = XMLInputFactory.newInstance();
factory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
XMLStreamReader reader = factory.createXMLStreamReader(input);

XMLInputFactoryクラスには同じようにXMLEventReaderを取得するメソッドもあります。

イベントの取得とループ

イベントの取得とループはこんなコードになります。

while (reader.hasNext()) {
  int c = reader.next();
  switch (c) {
    case XMLStreamReader.START_ELEMENT:
      break;
    case XMLStreamReader.END_ELEMENT:
      reader.getName();
      break;
    case XMLStreamReader.CHARACTERS:
      String text = reader.getText();
      break;
    default:
      break;
  }
}

IteratorのようなイメージでhasNextを使いループを記述します。next()を実行することで、イベントが発生するため、そのイベントごとに処理を記述していくだけになります。SAXよりも簡単に書けることが解るでしょう。尚、EventReaderの場合は、nextの代わりにnextEventを使い、イベントを発生させます。

改行コードがおかしい件

さて、問題がありまして、XMLStreamReader.CHARACTERSなどで取得したテキストのサイズがどうも一致しないケースが発生していました。調べてみると、どうも改行コードがすべてCRに変換されてしまっているようです。例えLFであってもです。CRLFの場合は文字数がずれる為、おかしな事にもなっていました。
結局はテキストを取得した後に、ファイルで使用されている改行コードに置換して対処をしましたが、バグなのでしょうかね。

String text = reader.getText();
text.replaceAll("\n", "\r\n");