Design Pattern Toolkit (DPTK) は Eclipse 対応テンプレート・エンジンで、カスタマイズ可能なモデル駆動アーキテクチャーの変換に基づいてアプリケーションを作成することを目的としています。前回の記事では、DPTK に備わったコード生成機能の基本を紹介しました。今回は、テンプレートからモデル・データにアクセスする方法について詳しく説明します。
DPTK パターンを作成するために十分理解しておかなければならないことは、データ・モデルへのアクセス方法、そして用意されている DPTK タグの使用方法の 2 つです。今回は前者に注目して、DPTK クエリー言語 (簡易化された XPath と非常によく似たクエリー言語) と、モデルを読み取ってそのデータをテンプレート出力に直接書き込む単純なタグをいくつか取り上げます。
Design Pattern Toolkit の詳細を調べる場合、またはダウンロードする場合には、IBM alphaWorks にアクセスしてください。
DPTK におけるデータ・モデルは、DPTK テンプレートに対しては DOM (Document Object Model) として提示されます。データは通常、XML ファイルまたは XML ストリングからのものが使用されますが、Java™ ソース・ファイルやフラット・ファイルなど、その他のソースのデータを使用することもできます。DPTK テンプレートでさえも、パターンに含まれるモデルのソースとして使用されてきました。例えば DPTK パターンから JET パターンにマイグレーションするテンプレートなどです。
このように、データ・モデルを作成可能なソースには多数のものが考えられますが、データ・モデルは常に DOM としてアクセスされます。そしてこの DOM へのアクセスには常に、クエリー式を 1 つまたは複数の属性として許容する DPTK タグが使用されます。
DPTK には、モデルを読み取り、その情報をテンプレートの出力に書き込む 3 つの単純なタグがあります。それぞれのタグごとに node 属性があり、この属性が DOM 内の単一モデル・ノードを記述するクエリー式を使用します。ノードが検出されると、タグがそのノードに対して特定のアクションを実行します。
この 3 つのタグのそれぞれが書き込む指定モデル・ノードの特性は、以下のとおりです。
-
<content>- node 属性で記述された特定ノードのコンテンツ (XML ファイル内の開始タグと終了タグで囲まれたテキスト) を書き込みます。 -
<attr>- 指定されたノードの属性のうちの 1 つの値を書き込みます。 -
<dump>- 指定されたノードの下にある DOM サブツリーの XML 表現を書き込みます。
この 3 つのタグを使用すると、テンプレートの作成が単調とは言わないまでも簡単になります。つまり、生成された成果物のコンテンツのどのセクションが動的であるかを判断して、テンプレートがまさに必要とする動的データのモデルを作成します。テンプレートの動的コンテンツ・セクションは、正しいモデル・ノードを対象とするクエリー式を使用した適切な <content>、<attr> または <dump> タグで簡単に置き換えられます。ここで出てくる一般的な質問は、任意の複合 DOM から正しいノードを取得するクエリー式はどうやって作成するのか、ということです。
- Import From Project Interchange ウィザードを使用して、この記事に記載したダウンロード・ファイル dataModelPattern.zip から Data Model Pattern プロジェクトをインポートします。
- エディターに write.pat テンプレートを開いて、モデル・データを書き出す 3 つの DPTK タグそれぞれの例を確認します (図 1)。
図 1. write.pat テンプレート
上記パターンのためのサンプル入力モデルは、以下の simple.xml にあります。
図 2. simple.xml
- サンプル入力モデルをこのパターンで変換するには、モデル (simple.xml ファイル) を選択して右クリックし、コンテキスト・メニューから Apply Pattern を選択します。
図 3. パターンによるテンプレートの変換
- モデルの変換に使用するパターンを選択するように求めるプロプトが表示されます (図 4)。
図 4. 選択可能なパターン
-
Data Model Pattern を選択し、OK をクリックします。パターンが正常に適用されたことを通知する情報メッセージ・ボックスが表示されるはずです。
パターンを適用した結果として、write.txt ファイルが含まれる Resultsという名前の新規プロジェクトが作成されます。write.txt ファイルを開くと、上記の write.pat テンプレート内の DPTK タグが simple.xml の入力モデルからのデータをどのようにして書き出したかを確認できます。
図 5. write.txt
DPTK クエリー式は、DOM をどのようにトラバースするかを記述するストリングです。トラバースは、単一のノードまたは複数のノードで終了させることも、あるいはどのノードでも終了させないことができます。DPTK クエリー式の結果は、言うなればナビゲーションの終了地点にあるノードのセットです。node または nodes 属性によってクエリー式をタグに渡すということは、つまりタグに対して、クエリー式の記述に従ってモデルをトラバースし、式で得られたノードに作用するように指示することになります。
慣例では、node 属性は結果が単一のノードになるクエリー式を指定します。式の結果が複数のノードになった場合は、最初のノードだけが使用されます。式によってノードが得られなかった場合は、エラーがスローされます。一方、nodes 属性は結果が任意の数 (ゼロを含む) のノードになるクエリー式を指定します。
構文としては、クエリー式には開始ノードがあり、これに関連ノード間を移動する方法を記述する一連のステップが続きます。以下の構文の違いによって、開始ノードは 2 種類に分けられます。
- 文書ノード (XML 入力内の上位要素の親) で開始するには、クエリー式の先頭をスラッシュ (/) にします。
- DOM 内のその他のノードで開始するには、クエリー式の先頭を、クエリー式が解釈される際に該当ノードに関連付けられる変数名にします。変数名を特定のノードに関連付けるには、<iterate>、<useNode>、<exists> および <extend> などのタグを使用できます。
クエリー式は、以下のノード収集シーケンスを組み立てることによって処理します。
- 最初の収集結果には、開始ノードだけが含まれます。
- 2 番目の収集結果には、最初のステップが記述する方法で開始ノードから到達可能なすべてのノードが含まれます。
- 3 番目の収集結果には、2 番目のステップが記述する方法で、2 番目の収集結果に含まれるいずれかのノードから到達可能なすべてのノードが含まれます。
- クエリー式の最後のステップ中に収集された最終的なノードの集合が、クエリー式によって得られたノードのセットです。
- クエリー式にステップがない場合、クエリー式の結果は開始ノードとなり、その後のフィルタリングは保留にされます。
DPTK クエリー式言語には、以下のように、モデルのトラバースを指定するための数種類のステップが用意されています。
-
親ステップ: ノードから、そのノードの親に移動します。
構文:.. -
子ステップ: ノードから、そのノードの子のうちの指定された名前を持つすべての子ノードに移動します。
構文:child-node-name -
すべての子ステップ: ノードから、そのノードのすべての子に移動します。
構文: *
図 6. クエリー式
図 6 に、異なる種類のステップで構成された 2 つの DPTK クエリー式を示します。最初の /portlet/*/link toPage='6' は文書 (portlet 要素の親) から開始し、以下の 3 つのステップで構成されています。
- 最初のステップ portlet で、文書の子で「portlet」という名前を持つすべてのノードを収集します。
- 2 番目のステップ「*」で、「portlet」という名前を持つノードのすべての子ノードにナビゲートします。
- 3 番目のステップ link toPage='6' で、「link」という名前で toPage 属性の値が「6」のすべてのページ・ノードの子にナビゲートします。
2 つ目のクエリー式 curlink/../.. は、変数 curlink (先頭にスラッシュがないため、最初のトークンは変数名となる) に関連付けられたノードから開始し、開始ノードの親、そしてその親にナビゲートします。指定した変数名が前の DPTK タグによって正しいノードに正確に関連付けられることを確実にするのは、パターン作成者の責任です。
以下のリストは、Eclipse にロードしたサンプル・パターンの complex.xml ファイルに含まれるコンテンツです。このファイルには、水泳チームのメンバーに関する情報が保管されています。
リスト 1
<swim>
<meet host-team='02' pool="Milburne" >
<event number="1" gender="F" distance="400" stroke="medly" relay="true" />
<event number="2" gender="M" distance="400" stroke="medly" relay="true" />
<event number="3" gender="F" distance="100" stroke="freestyle" relay="false" />
<event number="4" gender="M" distance="100" stroke="freestyle" relay="false" />
<event number="5" gender="F" distance="100" stroke="butterfly" relay="false" />
<event number="6" gender="M" distance="100" stroke="butterfly" relay="false" />
<event number="7" gender="F" distance="100" stroke="backstroke" relay="false" />
<event number="8" gender="M" distance="100" stroke="backstroke" relay="false" />
<event number="9" gender="F" distance="100" stroke="breaststroke" relay="false" />
<event number="10" gender="M" distance="100" stroke="breaststroke" relay="false" />
<event number="11" gender="F" distance="400" stroke="free" relay="true" />
<event number="12" gender="M" distance="400" stroke="free" relay="true" />
<swimmer name="Fred" teamref="01">
<entry event="2" />
<entry event="10" />
<entry event="12" />
</swimmer>
<swimmer name="Sam" teamref="02">
<entry event="6" />
<entry event="8" />
</swimmer>
<swimmer name="Mary" teamref="01">
<entry event="5" />
<entry event="9" />
<entry event="11" />
</swimmer>
<team id="01" name="Eastwood" />
<team id="02" name="Westlake" />
</meet>
</swim>
|
このデータは正規化されているため、値は 1 度だけ保管され、さまざまな要素で外部キーを使用する必要があります。例えば、Mary のチーム名を取得するには、ID 値が 01 の <team> 要素を見つけます。同様に、Mary のイベントを見つけるには、彼女の <swimmer> 要素にネストされた <entry> 要素を繰り返し、エントリーの event 属性に一致する number 属性を持つ <event> 要素を検索します。
パターン・テンプレートでは、成果物を正確に生成するために繰り返しとフィルタリングの手法を使用することがよくあります。ここで、すべてのチーム、各チームの全メンバー、そして各水泳選手が参加するイベントをリストしたレポートを生成するテンプレートの例を作成してみましょう。
まず、すべてのチームの繰り返しから始めます。チームを表す要素の集合を <meet> で取得するには、文書から開始して、<swim>、<meet> 、<team> の順で要素をナビゲートします。このナビゲーションを記述する DPTK クエリー式は /swim/meet/team となります。この式を、以下のように <iterate> タグの nodes 属性で使用します。
<iterate nodes="/swim/meet/team" name="team"> </iterate> |
<iterate> タグは、このクエリー式に一致するすべてのノードを収集します。このタグは、この収集結果に含まれるそれぞれのノードごとに名前「team」を関連付けて、そのコンテンツを一度処理します。
チームごとに、チームの名前に続いてそのチームの水泳選手をリストした行を書き出す必要があります。<team> 要素は変数名「team」と関連付けられているため、チームの属性を参照するときには、この変数名を以下のように使用できます。
<iterate nodes="/swim/meet/team" name="team"> |
Team: <attr node="team" name="name"/>
</iterate>
<attr> タグ内ではクエリー式「team」がスラッシュで始まっていないため、最初のトークン「team」が変数名として使用されます。この変数名にはステップが続いていないので、このクエリー式の結果は単一のノードになります。この場合、この単一ノードは現行の <team> ノードです。<attr> タグには現行チームの name 属性を書き出す効果があります。
チーム名を書き込んだら、次にこのチームで水泳選手を繰り返します。特定の <team> 要素に関連付けられたすべての <swimmer> 要素を表すノードを収集するには、文書から <swim>、<meet>、そして <swimmer> 要素までナビゲートします。ただし、<meet> 要素から <swimmer> 要素にステップする際には、teamref 属性が現行チームの ID 属性と一致する <swimmer> 要素だけにナビゲートする必要があります。
このようなナビゲートを実行するクエリー式では、/swim/meet/swimmer teamref='%team(id)%' というように 3 つのステップ (最後のステップはフィルター付き) を使用します。<iterate> タグを最初の <iterate> 内にネストして、繰り返しのスコープ内で変数名「swimmer」を現行の <swimmer> 要素に関連付けることを指定します。
<iterate nodes="/swim/meet/team" name="team">
Team: <attr node="team" name="name"/>
<iterate nodes="/swim/meet/swimmer teamref='%team(id)%'" name="swimmer">
Swimmer: <attr node="swimmer" name="name" />
</iterate>
</iterate>
|
サンプルのデータ・モデル・パターンに上記のテンプレート・セクションを持つテンプレートを作成するには、以下の手順に従います。
- プロジェクトのルート・ディレクトリーに新規ファイルを作成し、このファイルに swimming.pat という名前を付けます。
図 7. 新規ファイルの作成
- 新規テンプレートを作成したら、モデルに適用するテンプレートを制御する control.pat ファイルを編集します。以前とは異なるモデルを使用しているので、前のモデルを前提とする write.pat テンプレートは適用できません。control.pat テンプレートを編集する際に変更する必要があるのは、1 つの <start> タグだけです。
図 8. 開始タグの変更
- これで、complex.xml ファイルのモデルにパターンを適用できます。このパターンが、swimming.txt ファイルを生成します。
図 9. モデルへのパターンの適用
- このテンプレートで最後に必要なのは、水泳選手ごとのイベントをリストすることですが、これを行うナビゲーションは多少複雑です。各 <swimmer> 要素にはいくつかの <entry> 要素がネストされており、これらの要素が持つ値を使用して正しい <event> 要素を検索します。繰り返しで使用するナビゲーションは現行の水泳選手から始まり、そこからネストされたすべての <entry> 要素をトラバースします。このクエリー式は、swimmer/entry となります。
各 <entry> 要素について、文書ノードから <swim>、<meet>、および <event> 要素をトラバースして、正しい <event> 要素までナビゲートします。最後のステップも、<event> 番号属性と <entry> イベント属性によってフィルタリングします。テンプレートは、以下のようになります。
図 10. 複合ナビゲーションを持つテンプレート
このテンプレートによって、以下のような出力ファイルが作成されます。
図 11. テンプレートの出力
イベントの 3 つの <attr> タグにはすべて、同じクエリー式があることに注目してください。<useNode> タグを内部 <iterate> タグに含めて正しい <event> 要素を変数名「event」に一時的に関連付けることによって、テンプレートを大幅に単純化できます。
図 12. 単純化したテンプレート
- 上記では <attr> タグの占めるスペースが少なくなっているため、次のようにテンプレートに一層整然とフォーマット設定した出力を作成させることができます。
図 13. テンプレートの出力
優れたテンプレートを作成する鍵は、モデル・データへのアクセス方法を理解することです。Design Pattern Toolkit には、DOM として表される内部モデルから要素にアクセスできる特殊なモデル・タグとデータ・アクセス・タグが用意されています。また、DPTK クエリー言語では単一のストリングで DOM 内のほとんどすべての場所に直接アクセスできるため、テンプレートがさらにコンパクトになります。この記事では、DPTK 式言語を説明し、この言語を適用してデータ・モデルへの効果的アクセス方法を作成する手順を実例で紹介しました。
この記事をレビューしてくださった Geoffrey Hambrick 氏に感謝します。
| 内容 | ファイル名 | サイズ | ダウンロード形式 |
|---|---|---|---|
| Code sample | DataModelArticle.zip | 7 KB | HTTP |
Chris Gerken は、IBM Software Services for WebSphere グループ内の Asset Reuse Enablement Team のメンバーで、Design Pattern Toolkit を考案して作成しました。
Roland Barcia は、ニューヨーク/ニュージャージー首都圏の IBM Software Services for WebSphere で認定 IT スペシャリストとして活躍しています。「IBM WebSphere: Deployment and Advanced Configuration」の共著者です。Roland についての詳しい情報は、彼の Web サイトにアクセスしてください。