前回から,新しいXMLパーサであるStAX (Streaming API for XML)を紹介しています。
イベントイテレータAPI
前回はカーソルAPIについて解説しました。カーソルAPIではイテレータのようにXMLをパースしていくことができ,パースの制御をアプリケーションで行なうことが可能です。
しかし,イベントを番号で扱い,イベントによりパーサから取得できる情報が異なるなどの問題もあります。
それに対して,今回紹介するイベントイテレータAPIはイベントをクラスで表します。取得できる情報はイベントに内包されているため,取得できる情報を容易に判別することができます。
それでは,前回使用したサンプルをイベントイテレータAPIで書き直してみましょう。
サンプルのソース | EventIteratorSample1.java |
---|
このサンプルも要素が開始されると,その要素名を出力します。
public EventIteratorSample1(String xmlfile) { // 1. パーサ用ファクトリの生成 XMLInputFactory factory = XMLInputFactory.newInstance(); XMLEventReader reader = null; BufferedInputStream stream = null; try { // 2. 入力に使用するファイルの設定 stream = new BufferedInputStream( new FileInputStream(xmlfile)); // 3. パーサの生成 reader = factory.createXMLEventReader(stream); // 4. イベントループ while (reader.hasNext()) { // 4.1 イベントを取得 XMLEvent event = reader.nextEvent(); // 4.2 StartElementであれば名前を出力 if (event.isStartElement()) { StartElement element = (StartElement)event; System.out.println("Name: " + element.getName()); } } } catch (FileNotFoundException ex) { System.err.println(xmlfile + " が見つかりません"); } catch (XMLStreamException ex) { System.err.println(xmlfile + " の読み込みに失敗しました"); } finally { // 5. パーサ,ストリームのクローズ if (reader != null) { try { reader.close(); } catch (XMLStreamException ex) {} } if (stream != null) { try { stream.close(); } catch (IOException ex) {} } } }
前回のカーソルAPIの場合と異なる部分を赤で示しました。
パーサ用のファクトリはカーソルAPIと同じでXMLInputFactoryクラスを使用します。しかし,パーサはインタフェースが異なります。
カーソルAPIではjavax.xml.stream.XMLStreamReaderインタフェースでしたが,イベントイテレータAPIではjavax.xml.stream.XMLEventReaderインタフェースが使われます。
このため,パーサの生成もXMLInputFactoryクラスのcreateXMLEventReaderメソッドを使用します。このメソッドも引数がストリーム,リーダ,XSLTで使用されるソースが使用できます。
イベントループは,パーサのhasNextメソッドで制御されることは同じですが,イベントの取得は異なります。
カーソルAPIではイベントは番号で区別していましたが,イベントイテレータAPIではイベントオブジェクトを使用します。これに応じて,メソッドも異なります。カーソルAPIがnextメソッド,イベントイテレータAPIは4.1で使用しているようにnextEventメソッドです。
イベントイテレータAPIで使用するイベントは,すべてjavax.xml.stream.events.XMLEventインタフェースの派生インタフェースとなります。このため,nextEventメソッドの戻り値の型もXMLEventインタフェースになっています。
XMLEventインタフェースの派生イベントはjavax.xml.stream.eventsパッケージで定義されており,13種類あります。それぞれカーソルAPIのイベントに対応したインタフェース名なので,すぐ分かるはずです。
たとえば,要素の開始はStartElementインタフェースです。
ただし,カーソルAPIには存在したCDATAとSPACEは,Charactersインタフェースでまとめて表されます。
XMLEventインタフェースにはオブジェクトがどのイベントであるか調べるためのユーティリティメソッドが定義されています。要素の開始であれば,4.2で使用したようにisStartElementメソッドになります。
カーソルAPIではXMLStreamReaderオブジェクトから取得していた情報は,イベントイテレータAPIではイベントオブジェクトから所得するようにします。
たとえば,StartElementインタフェースにはgetNameメソッド,getNamespacesメソッドなどが定義されています。
そこで,4.2のif文の内部ではStartElementオブジェクトからgetNameメソッドをコールして,要素の名前を取得しています。
このようにイベントをオブジェクトで表すことにより,カーソルAPIよりもシンプルなコードを記述することが可能になります。
さて,このサンプルを実行してみましょう。
XMLドキュメントは前回と同じname.xmlを使用しました。
<?xml version="1.0" encoding="utf-8"?> <names> <name> <first>Bob</first> <last>Dylan<last> </name> <name> <first>Paul</first> <last>Simon</last> </name> <name> <first>Pete</first> <last>Seeger</last> </name> </names>
実行結果を次に示します。
C:\stax>java EventIteratorSample1 names.xml Name: names Name: name Name: first Name: last Name: name Name: first Name: last Name: name Name: first Name: last
names.xmlでは名前空間を使用していないので,要素名だけが出力されました。名前空間が指定してあれば,カーソルAPIと同様に名前空間も一緒に出力されます。