第6回 2007年6月1日 応用Java (Java/XML)
前回までやったこと 「XMLパーサ」-- Java でXMLを処理 javax.xml.stream パッケージのパーサ イベントの種類の調べる 応用(1) – テーブルの利用 「要素の出現回数を調べる」 応用(2) – フィルタ的な処理 java.util.Map, java.util.Set 応用(3) – MS Office 2007 のファイルを処理する
本日(6/1)の講義内容 javax.xml.stream の処理の再設計 処理内容を複数のクラスに分ける SAX(Simple API for XML)の処理
(復習) パッケージとAPI javax.xml.stream XMLEventReader インタフェース XMLInputFactory クラス javax.xml.stream.events XMLEvent インタフェース サブインタフェース群 StartDocument, EndDocument, StartElement, EndElement, Characters
その他のパーサの利用 javax.xml.parsers パッケージ SAXパーサ、DOMパーサを提供 org.xml.sax パッケージ org.w3c.dom パッケージ
プログラムの基本部分(1) import javax.xml.stream.events.*; XMLEventReaderTest1.java import javax.xml.stream.*; import javax.xml.stream.events.*; import javax.xml.transform.stream.*; public class XMLEventReaderTest1 { public static void main( String[] args ) {
プログラムの基本部分(2) try { StreamSource source = new StreamSource( args[0] ); XMLInputFactory factory = XMLInputFactory.newInstance(); XMLEventReader reader = factory.createXMLEventReader( source );
プログラムの基本部分(3) int count=0; while( reader.hasNext() ) { XMLEvent event = reader.nextEvent(); if( event.isStartElement() ) { ((StartElement).event).getName(); : }
イベントの場合分けの工夫 処理をメソッドに分割する XMLEvent event = reader.nextEvent(); if( event.isStartElement() ) { startElement( (StartElement)event ); } else if( event.isEndElement() ) { endElement( (EndElement)event ); } :
クラスへの分割を考えてみる 文書の入力先とパーサの取得 イベントの場合分けと処理の呼び出し 各イベントごとの処理の内容
設計案1)単純に3クラスに ParserTest – 文書の指定とパーサの取得 EventCase – イベントの場合分けとメソッドの呼び出し EventProc – イベントの処理の内容の記述
文書の指定とパーサ取得 public class ParserTest { public static void main( String[] ) { try { Source s = new StreamSource( name ); XMLInputFactory factory = XMLInputFactory.newInstance(); XMLEventReader reader = factory.createXMLEventReader( s ); EventCase ec = new EventCase(); ec.dispatch( reader );
場合分けのクラス public class EventCase { public void dispatch( XMLEventReader r ); try{ EventProc proc = new EventProc(); while( r.hasNext() ) { XMLEvent event = r.nextEvent(); if( event.isStartElement() ) { proc.startElement(); } :
処理の内容のクラス public class EventProc { public void startElement( StartElement se) { : } public void endElement( EndElement ee ) { public void characters ( Characters ch ) {
もうひと工夫 イベントの場合分けはいつも同じ 表に出なくてもいいのでは? 1つの方法:「クラスの継承」 AbstractEventProcessor クラス イベントの場合分けと呼び出しを記述 EventProcessorクラス 処理の内容の記述 public class EventProcessor extends AbstractEventProcessor {
さらに厳密にする インタフェースの導入 メソッドの名前、型を常に同じに制約 public interface EventProcessorIF { public void startElement( StartElement es); public void endElement( EndElement ee ); public void characters( Characters ch ); : }
継承関係 public abstract class AbstractEventProcessor implements EventProcessorIF { public void process ( XMLEventReader r ) { while( r.hasNext() ) { XMLEvent event = r.nextEvent(); if( event.isStartElement( ) ) { startElement( (StartElement)event) ; } : public abstract void startElement(StartEement se );
SAXによる処理 javax.xml.parsers 最も初期から利用可能だったパーサ 目的、設計は「今回の工夫」と共通
javax.xml.parsers 最も抽象化されたレベル(JAXP) パーサを「取り出す」ための仕組みを提供 SAXParser, SAXParserFactory DocumentBuilder, DocumentBuilderFactory 唯一の手段ではないが、「標準」を提供 パーサの実装に制限は課さない
パーサを取得するパターン(1) SAXParserFactory spf = SAXParserFactory.newInstance(); SAXParser parser = spf.newSAXParser(); XMLReader reader = parser.getXMLReader();
再度 Factory の「パターン」! XMLInputFactory factory = XMLInputFactory.newInstance(); XMLEventReader reader = factory.createXMLEventReader( source ); Factoryクラスはまず自分のインスタンスを作る Factoryのインスタンスから実際に処理を行うインスタンスを得る
SAXの処理の特徴 XML文書を読み込みながら処理 特定の「節目」でイベントが発生 (イベント駆動型の処理) イベントの処理はHandlerが担当 ContentHandler(のサブクラス) ErrorHandler(のサブクラス)
XMLReaderへのHandlerの登録 XMLReader reader = parser.getXMLReader(); reader.setContentHandler( new MyContentHandler() ); reader.setErrorHandler( new MyErrorHandler() );
その後で、パーシングを開始 XMLReader reader …. : InputSource source = new InputSource( “sample.xml” ); reader.parse( source );
SAXの処理の特徴 XML文書の読み込みと処理が並行に進行 要素(タグ)ごとに逐次処理 読み込みと処理は同時に終了 (後処理には別の機構が必要)
ContentHandler の主要な仕事 startDocument() – パーシングの開始時 endDocument() – パーシングの終了時 startElement() – 要素(タグ)の開始 endElement() – 要素(タグ)の終了 characters() – 平文テキストの読み込み
ContentHandler その他の機能 名前空間の処理 妥当性の検証とWhite Spaceの処理 *以上は次回以降に利用
ErrorHandlerの仕事 3つのエラーレベル fatalError 文書名の間違い、不存在 XML文書として不適切(文法エラー) warning エラーではない不適切な記述