SAX について挙動を確認するためのサンプル・プログラムを作成してみました。
特に、これまで SAX なんて使ったことがなかった自分には、characters() の動きが、
想定外だったので、確認した内容を記録しておきます。
作成したサンプルですが、画面は以下のように3つの要素から構成されています。
上段の EditText で入力となる XML ファイルを指定し、
「ファイル読み込む」ボタンを押すと処理を開始し、
下段の EditText で出力ファイル名 (入力ファイル名 + .txt ) を表示しています。
以下はソースです。
main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <EditText android:id="@+id/edittext" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <Button android:id="@+id/button" android:text="ファイル読み込む" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:text="出力ファイル名:" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <EditText android:id="@+id/output" android:layout_width="fill_parent" android:layout_height="wrap_content" android:editable="false" /> </LinearLayout>
TestSaxActivity.java
package jp.kochi;import java.io.BufferedWriter; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import android.app.Activity; import android.os.Bundle; import android.os.Environment; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; public class TestSaxActivity extends Activity { private EditText mEdit; private Button mButton; private EditText mOutput; private BufferedWriter mFileOutput; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mEdit = (EditText) findViewById(R.id.edittext); mButton = (Button) findViewById(R.id.button); mOutput = (EditText) findViewById(R.id.output); mEdit.setText(getFilesDir() + "/"); mButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // ファイル名を取得 CharSequence name = mEdit.getText(); File file = new File(name.toString()); // 出力用 のファイル名をセット String output = file.getName() + ".txt"; mOutput.setText(output); try { // 出力ファイルオープン FileOutputStream out = openFileOutput(output, MODE_PRIVATE); mFileOutput = new BufferedWriter(new OutputStreamWriter(out)); // SAXのよるparse開始 parseSax(file); } catch (FileNotFoundException e) { e.printStackTrace(); } finally { if (mFileOutput != null) { try { mFileOutput.close(); } catch (IOException e) { e.printStackTrace(); } } } } }); } private void parseSax(File file) { SAXParserFactory factory = SAXParserFactory.newInstance(); try { SAXParser parser = factory.newSAXParser(); TestHandler handler = new TestHandler(); parser.parse(file, handler); } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } private void writeToFile(String text) { try { mFileOutput.append(text); } catch (IOException e) { e.printStackTrace(); } } private class TestHandler extends DefaultHandler { @Override public void startDocument() throws SAXException { super.startDocument(); writeToFile("startDocument()\n"); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { super.startElement(uri, localName, qName, attributes); writeToFile("startElement() - uri = " + uri + "\n"); writeToFile(" - localName = " + localName + "\n"); for(int i=0; i<attributes.getLength(); i++) { writeToFile(" - attr.localName = " + attributes.getLocalName(i) + "\n"); writeToFile(" - attr.Value = " + attributes.getValue(i) + "\n"); } } @Override public void characters(char[] ch, int start, int length) throws SAXException { super.characters(ch, start, length); String value = new String(ch, start, length); writeToFile("characters() - ch = \"" + value + "\"\n"); } @Override public void endElement(String uri, String localName, String qName) throws SAXException { super.endElement(uri, localName, qName); writeToFile("endElement() - uri = " + uri + "\n"); writeToFile(" - localName = " + localName + "\n"); } @Override public void endDocument() throws SAXException { super.endDocument(); writeToFile("endDocument()\n"); } } }
実行例を以下のようになります。
test.xml (入力ファイル)
<?xml version="1.0" encoding="UTF-8" ?> <test xmlns="http://www.hogehoge.com/hoge/2.0"> <dir id="d1"> previous <text>Sample text1</text> after </dir> </test>
test.xml.txt (出力ファイル)
startDocument() startElement() - uri = http://www.hogehoge.com/hoge/2.0 - localName = test characters() - ch = " " startElement() - uri = http://www.hogehoge.com/hoge/2.0 - localName = dir - attr.localName = id - attr.Value = d1 characters() - ch = " " characters() - ch = " previous " startElement() - uri = http://www.hogehoge.com/hoge/2.0 - localName = text characters() - ch = "Sample text1" endElement() - uri = http://www.hogehoge.com/hoge/2.0 - localName = text characters() - ch = " after" characters() - ch = " " endElement() - uri = http://www.hogehoge.com/hoge/2.0 - localName = dir characters() - ch = " " endElement() - uri = http://www.hogehoge.com/hoge/2.0 - localName = test endDocument()
test.xml.txt の内容を見ると分かるのですが、
characters() では、改行や空白が、そのまま拾われるようになっています。
しかも面倒?なことに、1回で全てを取得するわけではなく、
改行の1バイトのみを characters() が返している箇所があります。
これまで SAX を使ったことがある人には当然なのかもしれませんが、
使ったことがない自分には、ちょっと意外な動きでした。
この点は、要注意かと。