このブログの更新は Twitterアカウント @m_hiyama で通知されます。
Follow @m_hiyama

メールでのご連絡は hiyama{at}chimaira{dot}org まで。

はじめてのメールはスパムと判定されることがあります。最初は、信頼されているドメインから差し障りのない文面を送っていただけると、スパムと判定されにくいと思います。

参照用 記事

Xion/Java:チュートリアル原案 その1

現在、Xion ver 0.1は次のURLから取得できます。

基本的仕様はだいたい固まったので、大きな変更や拡張はもうしません。が、使い勝手が悪い所などはチマチマと変えていきます(ver 1.0になるまで)。

とりあえず、次の変更はされるでしょう。

  1. XionReader→XionParserと改名
  2. AtomicValue→SpecialValueと改名
  3. 式ハンドラーのコールバックatomicValue(which)がspecialValue(which, data)となる。
  4. 例外とエラーメッセージが整理される。

以下は、チュートリアル(一部)の下書きのつもりですが、変更を先取りしているので注意してください。

●全体の概要

Xion/Javaには、次の3つのツールがあります。

  1. パーザー(XionParser)-- 構文構成素に対応するイベントを発生させながら構文解析する。イベントはユーザー定義のハンドラ(XionExpressionHandler)が処理する。
  2. ローダー(XionLoader)-- Xionテキストから、Xionオブジェクトモデルに従ったオブジェクト構造を構築する。
  3. リアライザー(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;の形をしています):

  1. startObject(String tag)
  2. key(String name)
  3. endObject()
  4. startArray(String tag)
  5. endArray()
  6. stringValue(String tag, String data)
  7. integerValue(String tag, String data)
  8. decimalValue(String tag, String data)
  9. 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);
}
}