プル・パースの次はプッシュ・パースを行う API を考えていきます。
前回までは単に StAX の簡略版を作ってただけです。 今回はそれを SAX っぽく扱おうってだけです。
XMLEventHandler インターフェースとそのデフォルト実装
プッシュ解析を行うには、SAX の org.xml.sax.ContentHandler のような、各イベントに対するコールバック処理を定義するインターフェースが必要です。 このインターフェースの各メソッドの引数に、前回までに作成した XMLEvent インターフェースとそのサブクラスを援用しましょう:
package xmlparsing; import xmlparsing.events.*; public interface XMLEventHandler { void startDocument(StartDocument event); void endDocument(EndDocument event); void startElement(StartElement event); void endElement(EndElement event); void text(Text event); }
SAX の org.xml.sax.helpers.DefaultHandler と同じような、実装の際に用いるヘルパークラスも定義しておきましょう:
package xmlparsing; import xmlparsing.events.*; public class DefaultXMLEventHandler implements XMLEventHandler{ public void startDocument(StartDocument event) {} public void endDocument(EndDocument event) {} public void startElement(StartElement event) {} public void endElement(EndElement event) {} public void text(Text event) {} }
実際にプッシュ・パースを行う際には、このクラスのサブクラスを作成します。
XMLEventParser#pushparse() メソッド
XMLEventParser#pushparse() メソッドの実装例を見ていきましょう。 あくまで実装例。 ここではpullparse() メソッドの実装に pushparse() メソッドを用いています:
package xmlparsing; import javax.xml.transform.Source; import xmlparsing.events.*; public class XMLEventParser { /** プッシュ・パース */ public void pushparse(Source source, XMLEventHandler handler){ XMLEventIterator iterator = pullparse(source); while(iterator.hasNext()){ XMLEvent event = iterator.next(); switch(event.getEventType()){ case XMLEvent.START_DOCUMENT: handler.startDocument((StartDocument)event); break; case XMLEvent.END_DOCUMENT: handler.endDocument((EndDocument)event); break; case XMLEvent.START_ELEMENT: handler.startElement((StartElement)event); break; case XMLEvent.END_ELEMENT: handler.endElement((EndElement)event); break; case XMLEvent.TEXT: handler.text((Text)event); break; default: throw new RuntimeException( "Unknown XML Event appears : "+event.getEventType()); } } iterator.close(); } /** プル・パース */ public XMLEventIterator pullparse(Source source){...} }
XMLEventParser の使用例
ではプッシュ・パースの使用例を見ていきましょう。 まず、SAX と同じようにコールバック処理を定義するために、独自の XMLEventHandler オブジェクトを作成する必要があります。 必ずそうしなければいけないわけではありませんが、ここではDefaultXMLEventHandler クラスを拡張して XMLEventHandler オブジェクトを作成します:
public class MyEventHandler extends DefaultXMLEventHandler{ @Override public void startDocument(StartDocument event) { System.out.println("<?xml version=\"1.0\"?>"); } @Override public void endDocument(EndDocument event) { System.out.println("<!-- EOF -->"); } @Override public void startElement(StartElement event) { System.out.println("<"+event.getName()+">"); } @Override public void endElement(EndElement event) { System.out.println("</"+event.getName()+">"); } @Override public void text(Text event) { System.out.println(event.getText()); } }
あとは以下の手順でプッシュ・パースを行います:
- XMLEventParser オブジェクトの取得
- XMLEventHandler オブジェクトの取得
- プッシュ・パースの実行
具体的な Java コードは次のようになります:
XMLEventParser parser = new XMLEventParser(); // (1) XMLEventParser オブジェクトの取得 Source src = new StreamSource("sample.xml"); XMLEventHandler handler = new MyEventHandler(); // (2) XMLEventHandler オブジェクトの取得 parser.pushparse(src, handler); // (3) プッシュ・パースの実行
最初の方にも書きましたが、単にイベント・ハンドラに前回までに作った XMLEvent インターフェースとそのサブクラスを援用しているだけで、たいして難しいことはないかと思います。