ここでは前ページで説明した事例
の中で、クライアントからの要求を受け付けるサーブレット部分の説明をします。ここでクライアントからの要求(XML)をSAXを利用して解析しています。
SAXによるXML解析の概要
最初にSAXによるXML解析の概要を図示します。なおこの概念図はXML文書全体をStringとして保持している場合に有効です。XML文書がファイルの場合などは図の左下の構成が少し変わってきます。
ここの手順は
- SAXParserFactoryからSAXParserを生成
- XML全体をStringオブジェクトとして保持
- そのXMLを保持しているStringをStringReaderに設定
- そのStringReaderをInputSourceに設定
- XML解析結果からデータ保持クラスを生成するハンドラークラスを自前で作成
- InputSourceクラスと自前のハンドラークラスを引数にして、SAXParserのparseメソッドを実行
- ハンドラークラス(DefaultHandlerクラスを継承したもの)から結果のデータ保持クラスを取得
といった流れです。
ここで出てくるクラスのコンストラクタやメソッドについて、簡単に触れておきます。StringReaderなどは知っておいて損は無いのですが、その他については使用する上で最小限の説明となります。
ここで説明するSAXの使い方ではStringReaderクラスが出てきます。出てくるだけでここではこれのメソッドは使いません。ですが文字列を扱うときにこれを介することによって、操作しやすい場合があるので説明しておきます。
StringReaderのパッケージはjava.io.StringReaderです。
StringReader のコンストラクタ
コンストラクタ |
引数(パラメータ) |
説明 |
StringReader |
String 操作対象文字列 |
指定した文字列に対する文字列リーダーを生成する。
|
StringReaderに対する主なメソッド
メソッド |
戻り値 |
引数(パラメータ) |
説明 |
ready | boolean |
− |
設定した文字列から読み込み可能かを判定する。
|
read | int |
− |
設定した文字列の現在の位置から1文字を読み込み、その文字コード(ハッシュコード)が返る。文字列の終わりで読み込めないときは−1が返る。
返るのはintの文字コード(ハッシュコード)なので文字として使用するときは
(char)StringReader型変数.read();
のようにchar型に変換(キャスト)する。
|
char[] 格納先文字配列 , int 格納位置 , int 読み込み文字数 |
設定した文字列の現在の位置から指定した文字数分の文字を読み込み、指定した文字配列の指定位置に格納する。
戻り値として実際に読み込まれて文字配列に格納された文字数が返る。
指定文字数 ≦ 文字列リーダーの残り文字数のときは指定文字数
指定文字数 > 文字列リーダーの残り文字数のときは残り文字数
が戻り値となる。
文字列の終わりに達していたときは−1が返る。
|
skip | long |
long 読み飛ばし文字数 |
現在の読み取り位置から指定した文字数分だけ読み飛ばす。
戻り値として実際に読み飛ばしが行われた文字数が返る。
|
markSupportted | boolean |
− |
この文字列リーダーがmark操作可能かを判定する。
|
mark | void |
int マーク保持上限文字数 |
現在の読み取り位置にマーク付けを行う。先に読み進んだ後も、resetを発行することによりこの位置に戻ることが出来る。
引数として設定したマーク位置を保持したまま読み込める文字数の上限を指定出来る。元の文字列から読み込まれるため実際の上限は無いので、正の値を指定しておけばよい。
|
reset | void |
− |
読み込み位置をマーク付けした場所に戻す。マーク付けされていない場合は文字列の先頭に戻す。
|
close | void |
− |
文字列リーダーを閉じる。
|
InputSourceクラスを直接使う状況は、私の経験内ではありませんでした。ここでは必要最小限ということでコンストラクタの説明だけを書いておきます。
InputSourceのパッケージはorg.xml.sax.InputSourceです。
InputSource のコンストラクタ
コンストラクタ |
引数(パラメータ) |
説明 |
StringReader |
− |
引数無しのデフォルトコンストラクタ。後からsetByteStream、setCharacterStream、setPublicId、setSystemIdといったセッター系メソッドで入力ソースを指定する。
|
InputStream バイトストリーム |
バイトストリームを指定して新しい入力ソースを作成する。
|
Reader 文字ストリーム |
文字ストリームを指定して新しい入力ソースを作成する。
文字ストリームとしてStringReaderやFileReaderを指定すればよい。本サイトではStringReaderを使用した例で説明する。
|
String システム識別子 |
システム識別子を指定して新しい入力ソースを作成する。
|
XMLをSAXで解析するためのSAXParserクラスを生成するために使います。
SAXParserFactoryのパッケージはjavax.xml.parsers.SAXParserFactoryです。
SAXParserFactoryのコンストラクタはprotectedになっており、使うことはありません。staticで定義されているnewInstanceを使います。
SAXParserFactoryに対する主なメソッド
メソッド |
戻り値 |
引数(パラメータ) |
説明 |
newInstance | SAXParserFactory |
− |
新しいSAXParserFactoryを生成する。
|
newSAXParser | SAXParser |
− |
現在設定されているSAXParserFactoryから新しいSAXParserを生成する。
|
setNamespaceAware | void |
boolean |
生成したSAXParserが、XML名前空間をサポートするか否かを指定する。デフォルトはfalse、サポートさせる場合はtrue、させない場合はfalseを指定する。
|
setValidating | void |
boolean |
生成したSAXParserが、構文解析時にドキュメントを検証するか否かを指定する。デフォルトはfalse、サポートさせる場合はtrue、させない場合はfalseを指定する。
|
XMLをSAXで解析するためのクラスです。解析時に自作のハンドラークラスを登録しておきます。
XML解析を実行してXMLタグやデータが見つかる度、ハンドラークラスのメソッドがSAXParserから呼び出されます。
またSAXParserはスレッドセーフではありません。あるSAXParserインスタンスが複数のスレッドから同時に使用された場合、動作は保証されません。アプリ側でスレッドセーフな実装にしておく必要があります。
SAXParserのパッケージはjavax.xml.parsers.SAXParserです。
SAXParserのコンストラクタはprotectedになっており、使うことはありません。SAXParserFactoryのnewSAXParserメソッドで生成します。
この後に例示するサンプルで使用するものを説明します。
SAXParserに対する主なメソッド
メソッド |
戻り値 |
引数(パラメータ) |
説明 |
parse | void |
InputSource 入力ソース , DefaultHandler ハンドラークラス |
指定した入力ソースの内容を、指定したハンドラークラスを使用してXMLとして構文解析する。
|
File 入力ファイル , DefaultHandler ハンドラークラス |
指定した入力ファイルの内容を、指定したハンドラークラスを使用してXMLとして構文解析する。
|
XMLをSAXで解析するときの、SAX2仕様におけるイベントハンドラの基底クラスです。
アプリケーション側はこのDefaultHandlerを継承したハンドラークラスを作成しておきます。ハンドラークラスではDefaultHandlerに定義されているメソッドのうち必要なものをオーバーライドして定義します。このメソッドはSAXParserから呼び出されるので、適宜データを保持して最終的にデータ保持クラスを返せるようにすれば良いでしょう。
DefaultHandlerのパッケージはorg.xml.sax.helpers.DefaultHandlerです。
ここはオブジェクト指向的な説明を加えておきましょう。
SAXParserで構文解析をするときにDefaultHandlerを継承したハンドラークラスを指定します。SAXParserでは構文解析でイベントが発生したときに、DefaultHandlerで定義しているメソッドを呼び出します。
このときに指定したハンドラークラスの、DefaultHandlerクラスのメソッドをオーバーライドしたメソッドが呼ばれます。ハンドラークラスに未定義のものはスーパークラスであるDefaultHandlerクラスのメソッドが呼び出されるという仕組みです。
そしてDefaultHandlerでは何もしない空メソッドとして定義されているため、指定したハンドラークラスで未定義のものはイベントが発生しても何も処理はされません。
DefaultHandler のコンストラクタ
コンストラクタ |
引数(パラメータ) |
説明 |
DefaultHandler |
− |
ハンドラークラスのデフォルトコンストラクタ。
|
この後に例示するサンプルで使用するものを中心に説明します。ハンドラークラスではこの中で必要なものをオーバーライドして定義しておきます。最低限としてはサンプルでも例示しているstartElement、endElement、characters、endDocumentでしょうか。
DefaultHandlerに対する主なメソッド
メソッド |
戻り値 |
引数(パラメータ) |
説明 |
startDocument | void |
− |
文書の開始通知を受け取る。
解析結果をファイル出力するなら初期作成をしたり解析結果のデータ保持クラスを初期化したりなど、必要な初期処理を行うことが出来る。
|
endDocument | void |
− |
文書の終了通知を受け取る。
解析中は内部保持していたデータから結果用データ保持クラスを作成したり、解析に使用したデータ領域の開放や終了処理などを行うことが出来る。
|
startElement | void |
String URI , String XMLタグ名 , String 修飾名 , Attributes XML属性 |
XML要素の開始通知を受け取る。
引数としてタグ名を受け取れるので、それが想定されているものか判定できる。またタグに対するデータ用の領域確保などを行う。
|
characters | void |
char[] 文字 , int 開始位置 , int 文字数 |
要素内の文字を受け取る。
文字は文字配列として渡されるので、開始位置・文字数と併せて実データを取得する。例えばstartElementメソッドでStringBufferを確保し、charactersメソッドでStringBuffer.append(受けた文字配列, 受けた開始位置, 受けた文字数);としてやればよい。
|
endElement | void |
String URI , String XMLタグ名 , String 修飾名 |
XML要素の終了通知を受け取る。
引数として受けたタグ名に対する、データの取り込みが終わったことが分かる。例えばcharactersメソッドでStringBufferに貯めたデータをtoStringで文字列として保持したり、あるいはタグに対する最終的なデータ型に変換して保持したりする。
|
ここまでSAXによるXMLの利用法について概念図と関連する主なクラスとそのメソッドについて説明しました。
しかしこれまでの説明を見てもピンと来ないとおもいます。
そこで具体的なサンプルを元にした説明を次ページ以降でしていこうと思いますが、サンプル作成中ですのでお待ちください。
|