Javaによるxml文書解析のための便利なサンプルひな形(SAX編)
xml文書の解析は、様々な場面で出てくる汎用的なTipsです。
特に最近では、異なるシステム間でのデータのやりとりや、Webサービスの戻り値としても、XMLが使われることも多いため、私も、いろいろなプロジェクトで使ってきました。
そして、毎回、最初のひな形を作るのにある程度時間をかけてしまうため、初めから、一通りxml文書を解析できるひな形をメモしておこうと思います。
xml文書の解析の際には、Domを使う方法とSAXを使う方法があります。
SAXは、文書を先頭から順に読み込んでいき、エレメントの開始や終了など、タグの出現タイミングで、ハンドラを起動します。
ハンドラとは、「ハンドリングするもの」という意味で、SAX型の解析では、このハンドラをあらかじめ定義しておき、対象のタグのところで様々な加工を行うことができます。
Dom型の解析の際には、xml文書全体を読み込んで、ツリー構造を構築してから解析・操作を行うため、文書の大きさに比例して多くのメモリが必要になりますが、SAX型では、文書をベルトコンベアーのように処理していき、適宜ハンドラを起動するので、Domに比べてメモリ消費が少なくなる傾向があります。
そこで、今回のサンプルは、SAX型にしてみたいと思います。
まず最初に、ハンドラを定義します。デフォルトのハンドラの振る舞い(DefaultHandler)を拡張して、自分のハンドラを定義していきます。
SAXのハンドラに必要なことはほとんどDefaultHandlerがやってくれますので、あとは、自分固有の振る舞いを定義していくだけです。
定義する場合は、以下のように、新しくクラスを作ったほうがいいでしょう。それは、xml文書が変わるとハンドリングの仕方も変わる可能性があるためで、xml文書の種類の分だけクラスを作っておくと、それを使う側で簡単に切り替えることができるからです。
SAX型のハンドラ定義
package net.plusidea.parser; import org.xml.sax.Attributes; import org.xml.sax.helpers.DefaultHandler; public class GoogleNewsParser extends DefaultHandler { private boolean outFlg = false; private StringBuffer outSb; /** * ドキュメント開始 */ public void startDocument() { System.out.println("StartDoc"); outSb = new StringBuffer(); } /** * ドキュメント終了 */ public void endDocument() { System.out.println("EndDoc"); } /** * 要素の開始タグ読み込み時に毎回呼ばれる */ public void startElement(String uri, String localName, String qName, Attributes attributes) { if(qName.equals("title")){ outFlg = true; } if(qName.equals("link")){ outFlg = true; } if(outFlg){ System.out.println("StartElement:" + qName); } } /** * テキストデータ読み込み時に毎回呼ばれる */ public void characters(char[] ch, int offset, int length) { if(outFlg){ System.out.println("Data:" + new String(ch, offset, length)); outSb.append(new String(ch, offset, length)); } } /** * 要素の終了タグ読み込み時に毎回呼ばれる */ public void endElement(String uri, String localName, String qName) { if(qName.equals("title")){ outFlg = false; } if(qName.equals("link")){ outFlg = false; } } }
文書を先頭から読み込んでいき、タグの開始と終了の際に、毎回startElement,endElementが呼ばれます。
どのタグでも呼ばれますので、必要な情報をもつタグ名の時に何か加工を行えば、xml文書の中から特定のタグを抜き出すことは簡単にできます。
上記の例では、<title></title>または<link></link>に囲まれている要素だけを抜き出すようになっていますので、適宜タグ名を修正して使えば、どんなxml文書でも対応可能になります。
つぎに、上記で定義したSAXハンドラを実際に使うときには、以下のようにします。
作成したSAXハンドラを使う
SAXParserFactory spfactory = SAXParserFactory.newInstance(); SAXParser parser = spfactory.newSAXParser(); parser.parse(new File("test.xml"), new GoogleNewsParser()); //下の場合は、inはInputStream型の変数 //parser.parse(in, new GoogleNewsParser());
たいていの場合は、xmlファイルでしょうから、
parser.parse(new File(“test.xml”), new GoogleNewsParser());
で解析が実行できます。
たまに、String型であったり、Webのレスポンスをハンドリングしなければならないこともありますが、その時は、下の
parser.parse(in, new GoogleNewsParser());
を使ってください。
inはInputStream型の変数です。(parseメソッドはString型の引数を渡せないので、)StringをInputStream型に直す場合は別記事「」を参照してください。