DMDLユーザーガイド

この文書では、Data Model Definition Language (DMDL)およびDMDLコンパイラの利用方法について紹介します。

DMDLの記述

DMDLを利用してデータモデルを定義するには、「DMDLスクリプト」というファイルの中に、データモデルの名前やプロパティの構造を記述します。 DMDLスクリプトは拡張子を .dmdl としたUTF-8エンコーディングのテキストファイルで、一つのDMDLスクリプトに複数のデータを定義することも、複数のDMDLスクリプトを利用して必要なデータモデル一式を定義することもできます。

DMDLでは4種類のデータモデルを記述できます。

レコードモデルを定義する

レコードモデルはプロパティの一覧を持つデータ構造です。

レコードモデルを定義するには、DMDLスクリプトに次のように記述します。

<モデル名> = {
    <プロパティの一覧>
};

それぞれのプロパティは、プロパティ名のあとにプロパティの型を指定します。 また、一つのレコードモデルには複数のプロパティを定義できます。

<プロパティの名前> : <プロパティの型> ;

モデル名やプロパティ名の形式については 名前の形式 を、プロパティに利用可能な型は プロパティの型 を参照して下さい。

以下はモデル名が example_model 、プロパティがそれぞれ整数型の number , 文字列型の item_code , 日時型の last_updated である場合の記述です。

example_model = {
    number : INT;
    item_code : TEXT;
    last_updated : DATETIME;
};

名前の形式

データモデルやプロパティの名前は、次のような snake_case の形式でなければなりません。

  • 小文字のアルファベット、数字、アンダースコアのみ
  • 最初の文字と最後の文字にアンダースコアを使えない
  • アンダースコアを2つ以上続けて使えない
  • _option で終わるプロパティ名を使えない

また、以下の条件を満たすことを強く推奨しています。

  • 名前にはJavaの予約語を利用しない
  • 名前に含まれる各単語はアルファベットから始める(数字や記号から始めない) [1]

以下に名前の指定例を示します。

  • よい例
    • hello
    • good_model_name
    • better1
  • 悪い例
    • helloWorld
    • BAD_PROPERTY_NAME
    • worse_0
[1]名前の各単語を数字から始めた場合、ある条件下でテストドライバーの一部機能に問題が発生することが報告されています。

プロパティの型

それぞれのプロパティには次のような型を指定できます。

利用可能なプロパティの型
型の名前 説明
INT 32bit符号付き整数
LONG 64bit符号付き整数
FLOAT 単精度浮動小数点
DOUBLE 倍精度浮動小数点
TEXT 文字列
DECIMAL 10進数
DATE 日付
DATETIME 日時
BOOLEAN 論理値
BYTE 8bit符号付き整数
SHORT 16bit符号付き整数

データモデルを合成する

他で定義したデータモデルを合成して新しいレコードモデルを作成するには、次のように記述します。

<定義するモデルの名前> = <合成するモデル1> + <合成するモデル2> + ... ;

合成されたデータモデルは、対象のデータモデルが定義する全てのプロパティを持つことになります。

both = left + right;
left = {
    left_value : INT;
};
right = {
    right_value : TEXT;
};

上記の例では、以下のようなデータモデルを定義したことになります。

both = {
    left_value : INT;
    right_value : TEXT;
};

なお、合成するそれぞれのモデルが同じプロパティを定義している場合、そのプロパティは一つだけ定義されたことになります。 また、同じ名前で型が異なるプロパティが定義された場合、データモデルの合成は失敗してエラーになります。

データモデルを拡張する

他のデータモデルに新たにプロパティを追加したデータモデルを定義するには、次のように記述します。

<モデル名> = <対象のモデル> + ... + {
    <プロパティの一覧>
};

拡張されたデータモデルは、対象のデータモデルが定義するすべてのプロパティに加え、新たに定義したプロパティを持つことになります。

origin = {
    value : INT;
};
extended = origin + {
    extra : TEXT;
};

上記の例では、以下のようなデータモデルを定義したことになります。

extended = {
    value : INT;
    extra : TEXT;
};

このようにDMDLでは、他のデータモデルの定義や新たなプロパティの定義を組み合わせて、複雑なデータモデルを定義できます。

結合モデルを定義する

結合モデルは、2つのデータモデルに「結合」の操作を行って生成するデータモデルを表します。 出来上がるデータモデルはレコードモデルと同様に複数のプロパティを持つデータ構造ですが、Asakusa DSLの「マスタ結合演算子」で利用した際に結合条件などの情報を自動的に取り出せます。

結合モデルの定義で記述する情報は、以下の通りです。

  • 結合対象のデータモデル
  • 結合条件 (等価結合条件のみ)
  • 結合前後でのプロパティのマッピング

プロパティマッピングを行わない場合、次のような方法で結合モデルを定義します。

joined <結合モデル名> = <対象モデル1> % <結合キー1> + <対象モデル2> % <結合キー2>;

それぞれの 対象モデル には、他で定義したデータモデルの名前を指定します。 また、それぞれの 結合キー には、対象モデルに含まれるプロパティの名前をカンマ区切りで指定します。

上記の形式で定義した結合モデルは、それぞれの対象モデルに定義された全てのプロパティを持ち、それぞれの結合キーを順に等価比較して結合するような構造を表します。

たとえば、次のような結合モデル item_order を定義できます。

item = {
    code : LONG;
    id : TEXT;
    ...
};
order = {
    item_code : LONG;
    item_id : TEXT;
    ...
};
joined item_order = item % code, id + order % item_code, item_id;

定義された結合モデルは、 itemorder が定義する全てのプロパティを持ち、 item.code = order.item_code かつ item.id = order.item_id という条件で結合可能であることを表す構造になります。

この結合モデル定義の形式は記述が簡潔ですが、対象モデル間に同一のプロパティ名が含まれている場合は利用出来ません。 また、不要なプロパティもすべて含むデータモデルが生成されることに注意が必要です。 これらの問題を回避するためには、以下に示す プロパティのマッピング を利用して結合モデルを定義します。

プロパティのマッピング

結合時に不要なプロパティを削除したりプロパティの名前を変えるには、結合モデルの定義時にプロパティのマッピングを記述します。

joined <結合モデル名> = <対象モデル1> -> {
    <プロパティのマッピング1>
} % <結合キー1> + <対象モデル2> -> {
    <プロパティのマッピング2>
} % <結合キー2>;

プロパティのマッピングは、 <元のプロパティ名> -> <マッピング後のプロパティ名> ; の形式でいくつでも書けます。 また、マッピングを記述しなかったプロパティについては、結合後のデータモデルから除外されます。

Attention

プロパティのマッピングを利用する場合、結合キーは マッピング後の プロパティ名を指定する必要があります。 また、結合キーになるプロパティはマッピングで削除してはいけません。

以下はプロパティのマッピングを行いながら結合モデルを定義する例です。

item = {
    code : LONG;
    price : DECIMAL;
};
order = {
    item_code : LONG;
    amount : INT;
    datetime : DATETIME;
};
joined item_order = item -> {
    code -> code;
    price -> price;
} % code + order -> {
    item_code -> code;
    amount -> total;
} % code;

上記の例で、 item_order にはそれぞれ code , price , total という3つのプロパティが定義されます。 それぞれのプロパティには、順に結合前の item.code ( = order.item_code ) , item.price , order.amount の値がマッピングされます。 なお、 order.datetime は結合時に捨てられます。

Hint

結合キーに指定されたプロパティは、他の結合キーに指定されたプロパティと同じ名前にできます。 結合キーは等価結合に使われるので、常に同じ値になるためです。

結合キーの制約

結合モデルを定義する際に、それぞれの結合キーは次の制約をすべて満たす必要があります。

  • 結合キーに指定したプロパティの個数が一致する
  • 結合キーに指定したプロパティは、対応するものごとに同じ順序で並んでいる
  • 結合キーに指定したプロパティは、対応するものごとに同じ型である

集計モデルを定義する

集計モデルは、1つのデータモデルに「集計」の操作を行って生成するデータモデルを表します。 出来上がるデータモデルはレコードモデルと同様に複数のプロパティを持つデータ構造ですが、Asakusa DSLの「単純集計演算子」で利用した際にグループ化条件や集約関数などの情報を自動的に取り出せます。

集計モデルの定義で記述する情報は、以下の通りです。

  • 集計対象のデータモデル
  • グループ化条件
  • 集計方法

次のような方法で集計モデルを定義します。

summarized <集計モデル名> = <対象モデル> => { <集計方法> } % <グループ化キー> ;

対象モデル には、他で定義したデータモデルの名前を指定します。 グループ化キー には集計対象のグループ化に利用するプロパティ名を指定します。

集計方法 は、次のような形式でいくつでも指定できます。

<集約関数> <集計対象のプロパティ名> -> <集計結果のプロパティ名> ;

集計対象のプロパティは、グループ化キーで指定された値ごとにまとめられ、集約関数を適用した上で集計結果のプロパティに格納されます。 利用可能な集約関数は、 集約関数の種類 を参照して下さい。

Attention

グループ化キーは 集計結果の プロパティ名を指定する必要があります。 また、グループ化キーに指定するプロパティは、 any という集約関数のみを指定できます。

たとえば、次のような集計モデル item_order を定義できます。

order = {
    item_code : LONG;
    price : DECIMAL;
    ...
};
summarized order_summary = order => {
    any item_code -> code;
    sum price -> total;
    count item_code -> count;
} % code;

上記の例で、 order_summary にはそれぞれ code , total , count という3つのプロパティが定義されます。 集計は order.item_code ごとに行われ、それぞれのプロパティには、順に order.item_code の値 , order.price の合計 , 集計した個数がマッピングされます。

Hint

レコードの個数を計測する count には、グループ化キーになるプロパティを指定すれば、グループの個数を正しく計測できます。

集約関数の種類

次のような集約関数を利用できます。

集約関数 性質
any グループ化した中のいずれか一つの値を利用する
sum グループ化した中の値の合計を利用する
max グループ化した中の最大値を利用する
min グループ化した中の最小値を利用する
count グループ化した中の個数を利用する
集約関数の型マッピング

集約関数を利用した場合、その結果のプロパティ型は以下のように設定されます。 = は集計元と集計結果でプロパティの型が同じであることを示します。

集計元の型 any sum max min count
BYTE = LONG = = LONG
SHORT = LONG = = LONG
INT = LONG = = LONG
LONG = LONG = = LONG
DECIMAL = DECIMAL = = LONG
FLOAT = DOUBLE = = LONG
DOUBLE = DOUBLE = = LONG
BOOLEAN = N/A = = LONG
DATE = N/A = = LONG
DATETIME = N/A = = LONG
TEXT = N/A = = LONG

射影モデルを定義する

射影モデルは、他のモデルの一部を投影するデータモデルです。 射影モデル自体は実体のデータを持たず、他のデータモデルから「射影」として切り出した際のデータ構造を表します。

射影モデルは、Asakusa DSLの 多相データフロー 機能と組み合わせて利用します。 多相データフローは、Asakusa DSLで複数のデータモデルに対する共通の処理をまとめて定義するための記述方法です。 詳しくは 多相データフロー を参照してください。

射影モデルを定義するには、 projective というキーワードに続けてレコードモデルと同じ方法でプロパティを定義します。

projective <モデル名> = {
    <プロパティの一覧>
};

プロパティの定義方法は、レコードモデルの「 データモデルを合成する 」や「 データモデルを拡張する 」と同様に、他のデータモデルのプロパティ定義を利用することも可能です。

データモデルに射影を登録する

レコードモデルから射影を取り出すには、対応する射影モデルをレコードモデルにあらかじめ登録しておく必要があります。

レコードモデルに射影モデルを登録するには、レコードモデルの定義時に登録したい射影モデルを合成します。

<レコードモデル名> = <射影モデル> + ... ;

射影モデルを合成してレコードモデルを定義した場合、通常のデータモデルを合成した際と同様に、全てのプロパティが定義するレコードモデルに取り込まれます。

projective proj_model = {
    value : INT;
};

上記のように記述した場合、 proj_model に対応するJavaのデータモデルクラスは生成されず、代わりに同様のプロパティを持つインターフェースが生成されます。 このインターフェースを実装( implements )するデータモデルクラスを生成するには、次のようにデータモデル定義の右辺にこの射影モデルを利用します。

conc_model = proj_model + {
    other : INT;
};

射影モデルをデータモデル定義の右辺に利用した場合、その射影モデルが定義するプロパティは、左辺のデータモデルにも自動的に追加されます。 さらに、左辺のデータモデルは右辺に利用したすべての射影モデルをインターフェースとして実装します。

また、射影モデルに別の射影モデルを登録することもできます。 他の射影を持つ射影モデルをデータモデルに登録した場合、データモデルには関係する全ての射影がとりこまれます。

たとえば、以下の例で record は、 sub_proj , super_proj がどちらも射影として登録されます。

projective super_proj = { a : INT; };
projective sub_proj = super_proj + { b : INT; };
record = sub_proj;

プロパティ参照を定義する

レコードモデルおよび射影モデルには、複数のプロパティを単一のコレクションとして利用するための「プロパティ参照」を定義できます。

これらは固定長のリスト (java.util.List) またはマップ (java.util.Map) として利用でき、それぞれの要素はデータモデル内に存在するプロパティの参照を表します。 つまり、データモデル中のプロパティの値を変更するとリストやマップの値も変化し、リストやマップに対して変更を行うと、対応するプロパティの値が変化します。

このプロパティ参照を上手に利用すると、データモデル内に存在する「プロパティの繰り返し」を容易に処理できるようになります。

リスト型のプロパティ参照を定義する

リスト型のプロパティ参照を定義するには、データモデル内に <参照名> = {<参照先のプロパティ名>, ...} の形式で記述します。

m = {
    a : INT;
    b : INT;
    c : INT;
    ref = {a, b, c};
};

上記のように記述した場合、 INT 型のプロパティ a, b, c の他に、 ref という名前のリスト型プロパティ参照を定義します。 このとき、それぞれのプロパティは同じ型である必要があります。

この ref は要素にそれぞれ a, b, c の参照を持つ、固定長のリストです。 Javaにおける表現は プロパティ参照の対応付け を参照してください。

マップ型のプロパティ参照を定義する

マップ型のプロパティ参照を定義するには、データモデル内に <参照名> = {<キー> : <参照先のプロパティ名>, ...} の形式で記述します。 ただし、それぞれのキーは文字列リテラルの形式でなければなりません。

m = {
    a : INT;
    b : INT;
    c : INT;
    ref = {
        "A" : a,
        "B" : b,
        "C" : c,
    };
};

上記のように記述した場合、 INT 型のプロパティ a, b, c の他に、 ref という名前のマップ型プロパティ参照を定義します。 このとき、それぞれのプロパティは同じ型である必要があります。

この ref という要素にそれぞれ a, b, c の参照を持ち、それぞれ文字列 A, B, C のキーが対応づけられた固定長のマップです。 Javaにおける表現は プロパティ参照の対応付け を参照してください。

コメントの挿入

DMDLスクリプトにコメントを挿入するには、以下のように記述します。

  • -- または // 以下に続く文字列は改行されるまでコメントとみなされます。
  • /**/ で囲まれたブロックはコメントとみなされます。これは複数行にわたり有効です。

以下コメントの使用例です。

item = {
    code : LONG; -- XYZコード体系で表現される商品コード
    id : TEXT;
//  name : TEXT;
};

/*
order = {
    item_code : LONG;
    item_id : TEXT;
    name : TEXT;
};
*/

上記では itemcode プロパティの追加説明にコメントを使用しています。 また、 name はコメントアウトされているため無効になっています。 order はモデル定義の全体がコメントアウトされ無効になっています。

DMDLコンパイラの実行

作成したDMDLスクリプトからAsakusa DSLで利用可能なデータモデルを生成するには、DMDLコンパイラを利用します。

データモデルクラスの生成

DMDLスクリプトからJavaデータモデルクラスを生成する場合、Asakusa Frameworkの asakusa-dmdl-java-*.jarcom.asakusafw.dmdl.java.Main クラスを次の引数で起動します。

-output

出力先のディレクトリ

-package

生成するクラスのベースパッケージ名

-source

コンパイルするDMDLスクリプトやディレクトリ

-sourceencoding

DMDLスクリプトのエンコーディング (default: UTF-8)

-targetencoding

生成するJavaのエンコーディング (default: UTF-8)

-plugin

DMDLコンパイラのプラグインファイル (default: なし)

Note

-plugin で指定するコンパイラプラグインについては、 DMDLコンパイラプラグインの利用 も参照してください。

Javaクラスの対応付け

DMDLコンパイラは、DMDLで定義されたデータモデルごとに、対応するJavaのクラスやインターフェースを生成します。

生成するクラスやインターフェースは、次のような名前になります。

<ベースパッケージ名> . <名前空間> . model . <データモデル名>

ベースパッケージ名
DMDLコンパイラに指定したパッケージ名。
名前空間
データモデルの名前空間 」で指定した名前。 デフォルトは dmdl
データモデル名
DMDLスクリプトで定義したデータモデル名を、CamelCaseの形式 [2] に変換したもの。
[2]例: hello_world -> HelloWorld

プロパティの対応付け

DMDLコンパイラが生成するJavaのクラスやインターフェースには、データモデルに定義したプロパティごとに次の名前の公開メソッドがそれぞれ作成されます。

  • get <プロパティ名>
  • set <プロパティ名>
  • get <プロパティ名> Option
  • set <プロパティ名> Option

また、 TEXT 型のプロパティに限り、追加で下記の公開メソッドが作成されます

  • get <プロパティ名> AsString
  • set <プロパティ名> AsString

それぞれのプロパティの型は、次のようなJavaのデータ型に対応します。

DMDLとJavaのデータ型
型の名前 対応する型 (Option)
INT int (IntOption)
LONG long (LongOption)
FLOAT float (FloatOption)
DOUBLE double (DoubleOption)
TEXT Text (StringOption) [3]
DECIMAL BigDecimal (DecimalOption)
DATE Date (DateOption) [4]
DATETIME DateTime (DateTimeOption) [5]
BOOLEAN boolean (BooleanOption)
BYTE byte (ByteOption)
SHORT short (ShortOption)
[3]org.apache.hadoop.io.Text , ...AsStringjava.lang.String
[4]com.asakusafw.runtime.value.Date
[5]com.asakusafw.runtime.value.DateTime

プロパティ参照の対応付け

DMDLコンパイラは、それぞれのプロパティ参照に対して、次の名前の公開メソッドを作成します。

  • get<参照名>

また、上記メソッドの返戻値型は、リスト型のプロパティであれば java.util.List<プロパティの型>, マップ型のプロパティであれば java.util.Map<String, プロパティの型> となります。

なお、プロパティ参照を表すリストやマップは、以下の点においてJavaの標準と異なる点に注意が必要です。

  • プロパティの追加・削除などは不可能
  • List.set()Map.put() などによって値を変更しようとした場合、引数に渡したオブジェクト そのものを格納せず 、オブジェクトのコピーを格納する
  • リストの並び替え (Collections.sort(), List.sort() など) は利用できない

データモデルの属性

データモデルに「属性」を定義しておくと、DMDLコンパイラが生成するプログラムを拡張できます。

データモデルの説明

データモデルのドキュメンテーションを変更するには、データモデルの定義の直前に "<データモデルの説明>" を付与します。

"サンプルのデータモデル"
example = { ... };

データモデルの説明は、レコードモデルだけでなく全てのモデルで指定できます。

データモデルの説明が指定されない場合、データモデルの名前で代用します。

プロパティの説明

プロパティのドキュメンテーションを変更するには、プロパティ定義やマッピングの直前に "<プロパティの説明>" を付与します。

order = {
    "商品コード"
    item_code : LONG;
    "商品価格"
    price : DECIMAL;
};
summarized order_summary = order => {
    "グループ化した商品コード"
    any item_code -> code;
    "商品価格の合計"
    sum price -> total;
} % code;

プロパティの説明が指定されない場合、プロパティの名前で代用します。

データモデルの名前空間

生成するプログラムのパッケージ名を(一部)変更するには、データモデル定義の直前に @namespace(value = <パッケージ名>) を指定します。

このパッケージ名は、データモデルの名前と同様に snake_case の形式で記述します ( 名前の形式 を参照 )。 また、 . で区切って深い階層の名前も指定できます。

"名前空間付きのモデル"
@namespace(value = your.namespace)
example = { ... };

Attention

@namespace(value = "ex.a") ではなく @namespace(value = ex.a) のように直接指定します。

Tip

データモデルの説明と名前空間を同時に指定する場合、データモデルの説明を先に書きます。

データモデルの名前空間が指定されない場合、 dmdl という名前空間を利用します。

自動射影

利用可能なすべての射影をデータモデルに登録させるには、データモデル定義の直前に @auto_projection を指定します。

射影モデルが持つプロパティをすべて持つモデルに @auto_projection 属性を指定した場合、そのデータモデルには対象の射影が自動的に登録されます。

projective foo = {
    value1 : INT;
    value2 : LONG;
};
@auto_projection
bar = {
    value1 : INT;
    value2 : LONG;
    value3 : DOUBLE;
};

上記のように記述した場合、 bar には自動的に foo が射影として登録されます。

通常の場合、データモデルに登録される射影は、レコードモデルや射影モデルのプロパティ定義に直接指定された射影モデルのみです。 現在のところ、結合モデルや集計モデルに射影を登録するには、この自動射影を利用する方法のみが提供されています。

プロパティ参照の詳細

プロパティ参照の型を指定する

プロパティ参照の定義を行う際に、それらの型を明示的に指定することもできます(通常は、要素のプロパティから自動的に推論します)。

プロパティ参照の名前と = の間に、リスト型であれば {<参照先の型>}, マップ型であれば {:<参照先の型>} の形式で指定します。

m = {
    a : INT;
    b : INT;
    c : INT;
    ref_list : {INT} = {a, b, c};
    ref_alist : {:INT} = { "A" : a, "B" : b, "C" : c, };
};

なお、要素を持たないプロパティ参照を定義する場合、明示的な型の指定が必須になります。

m = {
    ref_list : {INT} = {};
    ref_alist : {:TEXT} = {:};
};

プロパティ参照のスタブを定義する

射影モデル内にプロパティ参照を定義する場合、明示的な参照先のプロパティを省略した「スタブ」を定義することが可能です。

projective something = {

    // INTの参照リスト
    ref_list : {INT};

    // TEXTの参照マップ
    ref_alist : {:TEXT};
};

プロパティ参照のスタブを持つ射影を合成したモデルにおいては、スタブと同じ名前、同じ型の参照を明示的に定義する必要があります。

プロパティ参照の合成

データモデルの合成元にプロパティ参照が含まれる場合、合成先にはそのプロパティ参照が引き継がれます。

p0 = {
    a : INT;
    ref = {a};
};

// ref = {a} が引き継がれる
model = p0;

複数のデータモデルを合成する際に同一のプロパティ参照が複数含まれている場合、スタブでないプロパティ参照が2つ以上存在すると曖昧となりエラーになります(または、すべてがスタブの場合もエラーになります)。 この場合、合成先のモデルでプロパティ参照を定義し直す必要があります。

p0 = {
    a : INT;
    ref = {a};
};

p1 = {
    b : INT;
    ref = {b};
};

m = p0 + p1 + {
    ref = {a, b};
};

または、特殊な記法として <参照名> = <データモデル名>.<参照名>; と記述することで、合成元の参照を明示的に指定できます。

p0 = {
    a : INT;
    ref = {a};
};

p1 = {
    a : INT;
    ref = {a};
};

m = p0 + p1 + {
    ref = p0.ref;
};

いずれの場合においても、合成元のすべての参照と、合成左記の参照が同じ型(リスト/マップ、要素の型)でなければなりません。

DMDLコンパイラプラグインの利用

DMDLコンパイラはプラグインの仕組みを備えており、DMDLの解析やデータモデルプログラムの生成などをある程度制御できるようになっています。

プラグインを利用するには、DMDLコンパイラの起動オプション -plugin にプラグインのJARファイルを指定します。

組み込みプラグイン

DMDLコンパイラには、標準で様々なプラグインが組み込まれています。 以下は、主な組み込みプラグインの一覧です。

  • データモデルの名前空間 を指定する
  • 自動射影 を行う
  • Writable インターフェースを実装する
  • TEXT 型のプロパティに ...AsString のメソッドを提供する
  • hashCode, equals, toString などの標準的なメソッドを実装

これらは、DMDLコンパイラの起動オプションを指定しなくても自動的に適用されます。

Direct I/Oとの連携

Direct I/Oと連携したバッチアプリケーションでは、Direct I/Oが提供する特別な データモデルの属性 を利用可能です。

詳しくは データの直接入出力 - Direct I/O を参照してください。

WindGateとの連携

WindGateと連携したバッチアプリケーションでは、WindGateが提供する特別な データモデルの属性 を利用可能です。

詳しくは 外部システムとの連携 - WindGate を参照してください。

DMDLコンパイラプラグインの開発

詳しくは DMDL開発者ガイド を参照して下さい。