Powered by SmartDoc

付録:SAXを用いた読み込み

SAX(Simple API for XML)は、もう一つの標準XML操作用APIです。DOMと違い、イベント駆動型のAPIなので使いこなすには多少慣れが必要ですが、DOMより数倍高速に動作し、メモリの使用量も少ないので、スピードの要求される処理や、巨大なファイルの処理に向いています。詳しくは、XML関係の書籍か、Webサイトを参照してください。

リスト[ReadBySAX.java]は、今回のサンプルデータリスト[XMLデータ]を読み込むプログラムです。主な流れは、

  1. SAXパーサを作成
  2. DataItemHandlerをSAXパーサに登録
  3. パース開始するとイベントが発生。DataItemを構築
  4. 結果表示

のようになっています。

ReadBySAX.java
import javax.xml.parsers.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;
import java.io.File;
import java.io.IOException;
import java.util.Stack;
import java.util.List;
import java.util.ArrayList;

public class ReadBySAX {

    public static void main(String [] args) {
	//データを読んで
	DataItem [] items = getDataItems("data.xml");
	//表示
	for (int i=0;i<items.length;i++) {
	    System.out.println("Name["+items[i].getName()+"]");
	    System.out.println("Cost["+items[i].getCost()+"]");
	    System.out.println("Note["+items[i].getNote()+"]");
	    System.out.println("--------");
	}
    }

    // filename から DataItem 配列
    static DataItem [] getDataItems(String filename) {
	DataItemHandler handler = new DataItemHandler();
        try {
	    getSAXParser().parse(new File(filename),handler);
        } catch (Exception e) {
	    e.printStackTrace();
            System.exit(1);
	}
	return handler.getDataItems();
    }

    // JAXP API
    static SAXParser getSAXParser() {
        SAXParserFactory spf = SAXParserFactory.newInstance();
        try {
            return spf.newSAXParser();
        } catch (Exception e) {
	    e.printStackTrace();
	    System.exit(1);
	}
	return null;
    }

    // SAX 用 イベントハンドラ
    static private class DataItemHandler extends DefaultHandler {

	List items = new ArrayList();
	DataItem currentItem;
	Stack tagStack = new Stack();

	DataItem [] getDataItems() {
	    DataItem [] ret = new DataItem[items.size()];
	    return (DataItem[])items.toArray(ret);
	}

	String getCurrentTag() {
	    return (String)tagStack.peek();
	}

	// タグの開始位置に来ると呼ばれる
	public void startElement(String namespaceURI,
				 String localName,
				 String qName,
				 Attributes atts) throws SAXException {
	    if (qName.equals("dataItem")) {
		currentItem = new DataItem();
	    }
	    tagStack.push(qName); // 現在のタグ名を保存
	}

	// 内容を読み取ったときに呼ばれる
	public void characters(char[] ch,int start,int length) throws SAXException {
	    String text = new String(ch,start,length).trim();
	    if (text.length()==0) return;//省略可能なスペース

	    if (getCurrentTag().equals("name")) {
		currentItem.setName(text);
	    } else if (getCurrentTag().equals("cost")) {
		currentItem.setCost(Integer.parseInt(text));
	    } else if (getCurrentTag().equals("note")) {
		currentItem.setNote(text);
	    }
	}

	// 終了タグに来たら呼ばれる
	public void endElement(String namespaceURI,
				String localName,
				String qName) throws SAXException {
	    if (getCurrentTag().equals("dataItem")) {
		items.add(currentItem);
	    }
	    tagStack.pop();
	}

    }

}
実行結果
java ReadBySAX

Name[コーヒー]
Cost[120]
Note[主食]
--------
Name[チョコレート]
Cost[180]
Note[オヤツ]
--------
Name[ノート]
Cost[150]
Note[いつでもどこでもアイデアを記録]
--------