ExcelでDSLしてみよう
それでは実際にExcelを使った外部DSLっぽいミニフレームワークを作成してみましょう。通常のプログラムやXMLと比較して、
メリット
Excelは表ですので、
デメリット
デメリットとしては、
今回のお題
今回のお題は
例で使用する
表1が電文のフォーマットやルールを記述した
この仕様書をもとに固定長電文を解析してから、
1234567890123456789012345678901234567890123 20081101user1 user1@examples.com 10 20081101user2 user2@examples.com 0 20081101user3 user3@examples.com 100 20081102user4 user4@examples.com 80 20081102user5 user5@examples.com 55
| No | データ名称 | 開始 | 長さ | 変換ルール | 
|---|---|---|---|---|
| 1 | 送信日 | 1 | 8 | Date型に変換 | 
| 2 | ユーザ名 | 9 | 10 | 両端空白除去 | 
| 3 | メールアドレス | 19 | 20 | 両端空白除去 | 
| 4 | ポイント | 39 | 5 | 両端空白除去 Integer型に変換  | 
Step1:ベタなコードで書いてみる
まずはDSLなどを使わずにべたにコードを書くとリスト1のようになります。
まず①で固定長電文のファイルを読み込み、
parseメソッドはデータの読み込み処理です。データがなくなるまで読み込み処理を繰り返します。④でそれぞれのデータ項目のサイズだけ順番にデータを読み込んでいます。同時にDate型への変換
public static void main(String[] args) throws Exception {
    byte[] messages = FileUtils.readFileToByteArray(  ┓
        new File("data.txt"));                        ┛①
    MessageParser parser = new MessageParser(messages);  ―②
    parser.parse();
}
private static class MessageParser {
    private int index = 0;
    private final ByteArray bytes;
    public MessageParser(byte[] bytes) {    ┓
        this.bytes = new ByteArray(bytes);  |
    }                                       ┛③
    public void parse() {
        while (index < bytes.getLength() - 1) {
            Map<String, Object> record =
                new HashMap<String, Object>();
            record.put("送信日", toDate(getString(8)));           ┓
            record.put("ユーザ名", trim(getString(10)));           |
            record.put("メールアドレス", trim(getString(20)));       |
            record.put("ポイント", toInteger(trim(getString(5))));  ┛④
            System.out.println(record);     ―⑤
        }
    }
    private String getString(int length) {
        String value = bytes.getString(index, length);
        index += length;
        return value;
    }
    private static Integer toInteger(String value) { ... }
    private static String trim(String value) { ... }
    private static Date toDate(String value) { ... }
}
{送信日=Sat Nov 01 00:00:00 JST 2008, ポイント=10, ユーザ名=user1, メールアドレス=user1@examples.com}
{送信日=Sat Nov 01 00:00:00 JST 2008, ポイント=0, ユーザ名=user2, メールアドレス=user2@examples.com}
{送信日=Sat Nov 01 00:00:00 JST 2008, ポイント=100, ユーザ名=user3, メールアドレス=user3@examples.com}
{送信日=Sun Nov 02 00:00:00 JST 2008, ポイント=80, ユーザ名=user4, メールアドレス=user4@examples.com}
{送信日=Sun Nov 02 00:00:00 JST 2008, ポイント=55, ユーザ名=user5, メールアドレス=user5@examples.com}
考察1:MessageParserがクラスになっているのはなぜ?
MessageParserクラスは連載の前回でもお勧めしたインナークラスとして実装されています。これはバイト配列の現在の読み込み位置である変数indexをフィールドとして保持したいからです。
もしクラス化せずにローカル変数で保持しようとすると、
Map<String, Object> record = new HashMap<String, Object>();
record.put("送信日", toDate(bytes.getString(index, 8)));
index += 8;
record.put("ユーザ名", trim(bytes.getString(index, 10)));
index += 10;
また、
ByteReader reader = new ByteReader(bytes);
String sendedDate = reader.readAsString(8);
String userName = reader.readAsString(10);
考察2:これからどうする?
リスト1はベタに書かれていて、
今回は電文内のデータ項目は4種類