XmlPullParserをイベントドリブン対応にしてみた。

XmlPullParserも基本SAXみたいに上から順番に解析するだけ。でもSAXと違ってコールバックしてくれないので解析処理とEventTypeを確認しながら実装しなくてはならないためコードが冗長的になる。
なのでSAXのコールバック的なインタフェースとアダプターを作った

クラスとか

  • XmlPullpaHandler:イベントハンドラ
  • XmlPullpaAdapter:イベントハンドラの処理を空実装したアダプタクラス
  • XmlPullpaException:例外クラス
  • XmlPullpaReader:XmlPullParserを使ってコールバックしてくれるリーダクラス

イベントハンドラ

package com.example.xml.helper;

public interface XmlPullpaHandler {
	/**
	 * 文書の解析開始
	 * @throws XmlPullpaException
	 */
	void startDocument() throws XmlPullpaException;

	/**
	 * 文書の解析終了
	 * @throws XmlPullpaException
	 */
	void endDocument() throws XmlPullpaException;

	/**
	 * 要素開始
	 * @param name
	 * @param depth
	 * @throws XmlPullpaException
	 */
	void startTag(String name, int depth) throws XmlPullpaException;

	/**
	 * 要素の終了
	 * @param name
	 * @param depth
	 * @throws XmlPullpaException
	 */
	void endTag(String name, int depth) throws XmlPullpaException;

	/**
	 * 属性データ
	 */
	void apperAttribute(String parent, String name, String value, int index)
			throws XmlPullpaException;

	/**
	 * 文字データ
	 */
	void apperText(String parent, String value) throws XmlPullpaException;

	/**
	 * 無視できる文字列
	 * @throws XmlPullpaException 
	 */
	void ignoreWhitespace() throws XmlPullpaException;
}

イベントハンドラの処理を空実装したアダプタクラス

package com.example.xml.helper;

public abstract class XmlPullpaAdapter implements XmlPullpaHandler {

	/**
	 * 文書の解析開始
	 * 
	 * @throws XmlPullpaException
	 */
	@Override
	public void startDocument() throws XmlPullpaException {
	}

	/**
	 * 文書の解析終了
	 * 
	 * @throws XmlPullpaException
	 */
	@Override
	public void endDocument() throws XmlPullpaException {
	}

	/**
	 * 要素開始
	 * 
	 * @param name
	 * @param depth
	 * @throws XmlPullpaException
	 */
	@Override
	public void startTag(String name, int depth) throws XmlPullpaException {
	}

	/**
	 * 要素の終了
	 * 
	 * @param name
	 * @param depth
	 * @throws XmlPullpaException
	 */
	@Override
	public void endTag(String name, int depth) throws XmlPullpaException {
	}

	/**
	 * 属性データ
	 */
	@Override
	public void apperAttribute(String parent, String name, String value,
			int index) throws XmlPullpaException {
	}

	/**
	 * 文字データ
	 */
	@Override
	public void apperText(String parent, String value)
			throws XmlPullpaException {
	}

	/**
	 * 無視できる文字列
	 */
	@Override
	public void ignoreWhitespace() throws XmlPullpaException {
	}

}

■例外クラス

package com.example.xml.helper;

public class XmlPullpaException extends Exception {
	private static final long serialVersionUID = 1L;

	public XmlPullpaException(String str) {
		super(str);
	}
}

■XmlPullParserを使ってコールバックしてくれるリーダクラス
getByteArrayFromURLメソッドは前の記事参照

package com.example.xml.helper;

import java.io.IOException;
import java.io.StringReader;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import android.content.res.XmlResourceParser;
import android.util.Xml;

public class XmlPullpaReader {
	private XmlPullpaHandler handler;
	private XmlPullParser xmlParser;

	public void setHandler(XmlPullpaHandler handler) {
		this.handler = handler;
	}

	public void setXmlParser(XmlPullParser xmlParser) {
		this.xmlParser = xmlParser;
	}

	public void parse(String xml){
		this.xmlParser = Xml.newPullParser();
		try {
			this.xmlParser.setInput(new StringReader(xml));
		} catch (XmlPullParserException e) {
			e.printStackTrace();
		}

	}

	public void parse(XmlResourceParser parser){
		this.xmlParser = parser;
	}
	
	public void read() {
		try {
			int eventType = xmlParser.getEventType();
			String currentTag = null;
			while (eventType != XmlPullParser.END_DOCUMENT) {
				
				switch(eventType){
				case XmlPullParser.START_DOCUMENT:
					this.handler.startDocument();
					break;
					
				case XmlPullParser.END_DOCUMENT:
					//while終了条件で判定するんでここには来なかったりする
					this.handler.endDocument();
					break;
					
				case XmlPullParser.START_TAG:
					currentTag = xmlParser.getName();
					this.handler.startTag(xmlParser.getName(), xmlParser
							.getDepth());
					// 属性とか
					for (int i = 0; i < xmlParser.getAttributeCount(); i++) {
						this.handler.apperAttribute(xmlParser.getName(),
								xmlParser.getAttributeName(i), xmlParser
										.getAttributeValue(i), i);
					}
					break;
					
				case XmlPullParser.END_TAG:
					this.handler.endTag(xmlParser.getName(), xmlParser
							.getDepth());
					break;
					
				case XmlPullParser.TEXT:
					if (xmlParser.isWhitespace() || xmlParser.isEmptyElementTag()) {
						this.handler.ignoreWhitespace();
					} else {
						this.handler.apperText(currentTag, xmlParser
								.getText());
					}
					break;
				}
				eventType = xmlParser.next();
			}
		} catch (XmlPullParserException e) {
			e.printStackTrace();
		} catch (XmlPullpaException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

■クライアント
XmlPullpaAdapterを継承した内部クラスをもっている

BR

public final static String BR = System.getProperty("line.separator");
package com.example.xmkfile;

import java.io.StringReader;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.util.Xml;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

import com.example.xml.helper.XmlPullpaAdapter;
import com.example.xml.helper.XmlPullpaException;
import com.example.xml.helper.XmlPullpaReader;

public class XmlPullpaClient extends Activity {
	private Button btRead;
	private TextView txtXmlData;
	private MyPullpaAdapter handler;

	/**
	 * XmlPullaAdapter実装クラス
	 */
	class MyPullpaAdapter extends XmlPullpaAdapter {

		@Override
		public void apperAttribute(String parent, String name, String value,
				int index) throws XmlPullpaException {
			txtXmlData.append("Attribute");
			txtXmlData.append(Util.BR);
			txtXmlData.append("    tag=" + parent + " " + name + "="
					+ value + " index=" + index);
			txtXmlData.append(Util.BR);
		}

		@Override
		public void apperText(String parent, String value)
				throws XmlPullpaException {
			txtXmlData.append("Text");
			txtXmlData.append(Util.BR);
			txtXmlData.append("    tag=" + parent + " value=" + value);
			txtXmlData.append(Util.BR);
		}

		@Override
		public void endDocument() throws XmlPullpaException {
			txtXmlData.append("End document");
			txtXmlData.append(Util.BR);
		}

		@Override
		public void endTag(String name, int depth) throws XmlPullpaException {
			txtXmlData.append("End Tag");
			txtXmlData.append(Util.BR);
			txtXmlData.append("    " + name + " depth=" + depth);
			txtXmlData.append(Util.BR);
		}

		@Override
		public void ignoreWhitespace() throws XmlPullpaException {
			txtXmlData.append("WhilteSpace");
			txtXmlData.append(Util.BR);
		}

		@Override
		public void startDocument() throws XmlPullpaException {
			txtXmlData.append("Start Docment");
			txtXmlData.append(Util.BR);
		}

		@Override
		public void startTag(String name, int depth) throws XmlPullpaException {
			txtXmlData.append("Start Tag");
			txtXmlData.append(Util.BR);
			txtXmlData.append("    " + name + " depth=" + depth);
			txtXmlData.append(Util.BR);
		}
	}

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		this.handler = new MyPullpaAdapter();

		this.txtXmlData = (TextView) findViewById(R.id.TextViewXml);
		this.btRead = (Button) findViewById(R.id.ButtonRead);
		this.btRead.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
//				readXmlResources();
				readXmlString();
			}
		});
	}

	/**
	 * リソースから
	 */
	private void readXmlResources(){
		Context context = getApplicationContext();
		XmlPullpaReader reader = new XmlPullpaReader();
		reader.setHandler(this.handler);
		reader.parse(context.getResources().getXml(R.xml.songs));
		reader.read();
		
	}

	/**
	 * 文字列から
	 */
	private void readXmlString(){
		XmlPullpaReader reader = new XmlPullpaReader();
		reader.setHandler(this.handler);
		reader.parse("<hoge>sample</hoge>");
		reader.read();
		
	}

}