現在、Xion ver 0.1は次のURLから取得できます。
- Xion-0.1 : http://www.chimaira.org/tmp/Xion-0.1.tgz
基本的仕様はだいたい固まったので、大きな変更や拡張はもうしません。が、使い勝手が悪い所などはチマチマと変えていきます(ver 1.0になるまで)。
とりあえず、次の変更はされるでしょう。
- XionReader→XionParserと改名
- AtomicValue→SpecialValueと改名
- 式ハンドラーのコールバックatomicValue(which)がspecialValue(which, data)となる。
- 例外とエラーメッセージが整理される。
以下は、チュートリアル(一部)の下書きのつもりですが、変更を先取りしているので注意してください。
●全体の概要
Xion/Javaには、次の3つのツールがあります。
- パーザー(XionParser)-- 構文構成素に対応するイベントを発生させながら構文解析する。イベントはユーザー定義のハンドラ(XionExpressionHandler)が処理する。
- ローダー(XionLoader)-- Xionテキストから、Xionオブジェクトモデルに従ったオブジェクト構造を構築する。
- リアライザー(XionRealizer)-- Xionテキストから、応用固有のオブジェクト構造を構築する。このとき、ユーザー定義のコンバーター(XionConverter)を登録したコンテキスト(XionRealizerContext)を使う。
いずれも使い方は簡単で、次のような感じです。
// inputは入力ストリーム
// UserHandlerはユーザー定義の式ハンドラー
// ---------------------
XionParser parser = new XionParser();
parser.setExpressionHandler(new UserHandler());
try {
parser.parse(input);
} catch (Exception e) {
System.out.println(e);
System.exit(1);
}
// パーズ完了
// inputは入力ストリーム
// ---------------------
XionLoader loader = new XionLoader();
Object xionModel = null;
try {
xionModel = loader.load(input);
} catch (Exception e) {
System.out.println(e);
System.exit(1);
}
// ロード完了
// inputは入力ストリーム
// contextはコンバーターを登録した変換コンテキスト
// UserTypeは応用固有データの型
// ---------------------
XionRealizer realizer = new XionRealizer();
UserType userModel = null;
try {
userModel = (UserType)realizer.realize(input, context);
} catch (Exception e) {
System.out.println(e);
System.exit(1);
}
// リアライズ完了
●使うための準備
xion.jarをクラスパスに含めれば、それでプログラミングも実行もできます。
例えば、
>set CLASSPATH=%CLASSPATH%;C:\JavaLib\Xion\xion.jar
●パーザーの使い方
例題として、Xionデータ(テキストファイル)を読み込んで、少し変わった構文(alternative syntax)で書き出すプログラムを作ってみます。代替構文を詳しく説明はしませんが、「改行とインデントを利用したbegin-end風の構文」と言えば見当は付くでしょう。
先に、入力のXionデータと実行結果を見てみましょう。
EmployeeList [
Person {
name : PersonNameJa "板東 トン吉",
tel : TelNo "03-0000-9999",
age : Age 26
},
Person {
name : PersonNameJa "園部 ハナ子",
tel : TelNo "04-1111-1111",
age : Age 22
}
]
>java XionAltPrinter EmployeeList.xion
array EmployeeList
object Person
"name" :
PersonNameJa "板東 トン吉"
"tel" :
TelNo "03-0000-9999"
"age" :
Age 26
end object
object Person
"name" :
PersonNameJa "園部 ハナ子"
"tel" :
TelNo "04-1111-1111"
"age" :
Age 22
end object
end array
XionParserを使うには、(先に述べましたが)次のようにすればOKです。
XionParser parser = new XionParser();
// handlerは自分で用意する。
parser.setExpressionHandler(handler);
try {
parser.parse(input);
} catch (Exception e) {
// エラー処理
// 必要なら、例外の種類ごとに
// エラー処理を分けて書く。
}
パージング(構文解析)中にコールバックされるハンドラー(XionExpressionHandler)は各自が書きます。ハンドラーはインターフェースXionExpressionHandlerを実装(implements)したクラスです。揃えるべきメソッド群は(いずれもpublic void ** throws XionHandleException;
の形をしています):
- startObject(String tag)
- key(String name)
- endObject()
- startArray(String tag)
- endArray()
- stringValue(String tag, String data)
- integerValue(String tag, String data)
- decimalValue(String tag, String data)
- specialValue(SpecialValue which, String data)
これらのメソッドがいつ呼ばれるかは名前から明らかでしょう。
以下がサンプルのコードです。
import java.io.*;
import org.chimaira.xion.*;public class XionAltPrinter {
public static void main(String[] args) {
if (args.length < 1) {
System.err.println("This program requires one argument.");
System.exit(0);
}
String filename = args[0];
File file = new File(filename);
Reader input = null;
try {
input = new FileReader(file);
} catch (Exception e) {
System.err.println(e);
System.exit(1);
}
// ver 0.1ではXionReaderだが、
// 次のバージョンで、XionReaderはXionParserに改名される。
XionParser parser = new XionParser();
// ver 0.1では以下の行を忘れるとNullPointer例外が出る。
// 次のバージョンでは例外は起きず、単に何もしないようになるだろう。
parser.setExpressionHandler(new XionAltPrinterHandler());
try {
parser.parse(input);
} catch (Exception e) {
System.err.println(e);
System.exit(1);
}
System.exit(0);
}
}class XionAltPrinterHandler implements XionExpressionHandler {
private int indent = 0;
private void doIndent() {
for (int i = 0; i < indent; i++) {
System.out.print(" ");
}
}
private void doWeakIndent() {
assert 1 <= indent;
for (int i = 0; i < indent - 1; i++) {
System.out.print(" ");
}
System.out.print(" ");
}public void startObject(String tag) throws XionHandleException {
doIndent();
System.out.println("object " + (tag == null? "" : tag));
indent++;
}
// ver 0.1ではXionUtil.escape は存在しない。
public void key(String name) throws XionHandleException {
doWeakIndent();
System.out.println("\"" + XionUtil.escape(name) + "\" : ");
}
public void endObject() throws XionHandleException {
indent--;
doIndent();
System.out.println("end object");
}
public void startArray(String tag) throws XionHandleException {
doIndent();
System.out.println("array " + (tag == null? "" : tag));
indent++;
}
public void endArray() throws XionHandleException {
indent--;
doIndent();
System.out.println("end array");
}
// ver 0.1ではXionUtil.escape は存在しない。
public void stringValue(String tag, String data) throws XionHandleException {
doIndent();
System.out.println((tag == null? "": tag + " ") +
"\"" + XionUtil.escape(data) + "\"");
}
public void integerValue(String tag, String data) throws XionHandleException {
doIndent();
System.out.println((tag == null? "": tag + " ") + data);
}
public void decimalValue(String tag, String data) throws XionHandleException {
doIndent();
System.out.println((tag == null? "": tag + " ") + data);
}
// ver 0.1では atomicValue(AtomicValue) だが、
// 次のバージョンでは specialValue(SpecialValue, String)
public void specialValue(SpecialValue which, String data) throws XionHandleException {
doIndent();
System.out.println(data);
}
}