Velocityテンプレート

今回はASTERIAでテンプレートを利用するときに使う技術であるVelocityテンプレートをご紹介します。主にフローのVelocityコンポーネントでの利用について解説していますが、パイプラインでも利用できます。

1. Velocityとは

VelocityとはApache jakartaプロジェクトで開発された「テンプレートエンジン」です。テンプレートエンジンとはどういうものであるかを説明するために、まずは単純なメール本文の作成にVelocityを利用する例をご紹介します。

例えば自社の主催するセミナーに参加していただいたお客様に対してお礼のメールを送信するケースを考えてみます。メール本文は次のような文章となります。

○○株式会社 山田太郎様

このたびは6月23日開催の「ASTERIA WARP体験セミナー」にご参加いただき
誠にありがとうございました。

。。。

ご質問等ございましたら営業担当、××(xxxx@infoteria.com)まで
お気軽にお問い合わせください。

セミナー参加者が10人いた場合は10人に対してメールを送ることになります。セミナーが毎月開催されるものであるなら毎月同じようなメールを送ることになるでしょう。

上記のようなお礼メールは誰に対して送信する場合でも内容はほとんど変わりません。この例の場合、送信先によって

  • 顧客の会社名
  • 顧客の氏名
  • セミナー開催日
  • セミナー名
  • 営業担当の名前
  • 営業担当のメールアドレス

だけを変更すれば残りの部分はそのまま使いまわすことができます。

このようなケースでベースとなるテキストに対し、一部を置き換えることで複数のテキストを生成できるようにする仕組みがテンプレートエンジンです。

この例のメール本文をASTERIAのVeloicityコンポーネントで作成する場合のテンプレート(ベースとなるテキスト)は次のようになります。

$flow.CorpName $flow.UserName様

このたびは$flow.SeminarDate開催の「$flow.SeminarName」にご参加いただき
誠にありがとうございました。

。。。

ご質問等ございましたら営業担当、${flow.StaffName}($flow.StaffMail)まで
お気軽にお問い合わせください。

先に置き換える個所として挙げた部分がすべて「$flow.xxxx」というキーワードに置き換えられています。(一箇所キーワードが「{}」で括られているところがありますが今は気にしないでください。)

このようにテキスト中に「$xxxx」というキーワードを埋め込むことによってそれを実際の値と置き換えたテキストを生成することができるのがVelocityです。単純なテキスト置換だけではなく指示子と呼ばれる命令文を使用することで簡単なロジックを組み込むこともできます。

2. リファレンス

Velocityでは「$xxxx」のようなキーワードをテンプレート中に埋め込むと述べましたが、この「$」で始まるキーワードとそれに付随するプロパティとメソッドのことをリファレンスと言います。「$」で始まる単語自体はVelocityのドキュメントでは「変数」と呼ばれていますが、フロー変数やシステム変数などのASTERIAの変数概念と区別するためにここでは「リファレンス変数」と呼びます。

フローのVelocityコンポーネントではあらかじめ次のリファレンス変数が設定されています。

Velocityコンポーネントのリファレンス
リファレンス変数 設定内容
$flow フロー変数
$local ローカル変数
$exvar 外部変数セット
$system システム変数
$in 入力ストリーム
$sys 汎用ユーティリティ
$xpath XPathユーティリティ
$encoding 出力エンコーディング

先の例では「$flow.xxxx」というリファレンスを使用しましたが、これはフロー変数を参照するリファレンスです。

2.1. プロパティ

リファレンスではプロパティとメソッドが使用できます。

プロパティを参照するにはリファレンス変数の後ろに「.」(ドット) を置き、それに続けてプロパティ名を記述します。

リファレンス変数「$flow」ではプロパティとしてフロー変数名を指定することができます。例えばフロー変数「CorpName」に「インフォテリア株式会社」が設定されている場合、「$flow.CorpName」は「インフォテリア株式会社」に置き換えられます。

プロパティによって取得されたオブジェクトからさらにプロパティやメソッドが使用できることもあります。

プロパティの例

$flow.UserName        - フロー変数「UserName」
$exvar.Exvar1.var1    - 外部変数セット「Exvar1」の変数「var1」
$system.RequestURL    - システム変数「RequestURL」

2.2. メソッド

メソッドを使用するにはリファレンス変数の後ろに「.」(ドット) を置き、それに続けてメソッド名を記述し、その後ろに「()」をつけてその中に引数のリストを記述します。引数には次のものが指定できます。

  • リファレンス
  • 文字列リテラル
  • 数値
  • 真偽値(true/false)

メソッドとプロパティの違いは識別子の後ろに「()」をつけて引数が指定できるかどうかだけです。メソッドに引数がない場合でも「()」と空のカッコを指定する必要があります。

メソッドの例

$in.array(0).text()        - 1番目の入力ストリーム
$flow.UserName.strValue()  - フロー変数「UserName」の文字列
$sys.formatDate($flow.date1, "yyyy/mm/dd") - 日付型のフロー変数「date1」
                                             をフォーマットして表示

2.3. 表記法

ASTERIAでの具体的なリファレンスの使い方を説明する前にリファレンスの表記法をまとめておきます。リファレンス変数、プロパティ、およびメソッドで使用可能な文字は以下のとおりです。

  • アルファベット (a・・z, A・・Z)
  • 数字 (0・・9)
  • ハイフン ("-")
  • アンダースコア ("_")

ただし識別子の先頭で使える文字はアルファベットのみです。つまり「$1ban」「$_temp」のようなリファレンス変数は認められませんし、「$日本語」のように日本語を使用することもできません。

有効なリファレンスの表記例

$flow.var1 - フロー変数「var1」
$in.text() - 入力ストリームの文字列
$sys.formatDate($flow.date1, "yyyy/mm/dd") - 日付型のフロー変数「date1」
                                             をフォーマットして表示

2.3.1. 正式表記

リファレンスは生成するテキスト本文の中に埋め込まれます。そのためリファレンスの直後に別の語が置かれることも珍しくありません。例えば一章の例の

$flow.UserName様

このたびは$flow.SeminarDate開催の。。。

などはリファレンスが後続の文字と切れ目なしに使用されている例です。

この例の場合はリファレンス直後の文字が「様」「開」とリファレンス識別子として使用できない文字のためVelocityがリファレンスの区切りを間違うことはありません。ですが、リファレンス直後の文字が英数字であった場合はどうなるでしょうか?また、フロー変数として「var1」と「var11」が定義されている場合「$flow.var11」はどのように解釈されるでしょうか?

これらの場合、Velocityは識別子として使用できない文字が現れたところをリファレンスの区切りとして扱います。つまり「$flow.var11」は決して「$flow.var1 + "1"」とは扱われませんし、「$flow.UserNameABC」では「UserNameABC」がプロパティ名として解釈されます。「UserNameABC」というプロパティが存在しない場合は「$flow.UserNameABC」という文字列がそのまま出力され、仮に「UserName」あるいは「User」というプロパティが存在したとしてもその値が出力されることはありません。

こうした場合に対応するときに使うのが正式表記です。正式表記ではリファレンスの「$」に続く部分を「{}」で括ります。

正式表記の例

${flow.UserName}ABC
${flow.var1}1
${in.text()}

正式表記を使用することでリファレンスの区切りを明示することができます。一章の例で「${flow.StaffName}($flow.StaffMail)まで」の部分で正式表記が用いられているのは、そうしないと後続のカッコによって「StaffName」がプロパティではなくメソッドとして解釈されてしまうためです。

2.3.2. 沈黙表記

前節でリファレンスで存在しないプロパティを指定した場合には「$flow.UserNameABC」のようにリファレンス指定の文字列がそのまま出力されると説明しましたが、このようにリファレンス文字列がそのまま出力される場合には次のものがあります。

  • 存在しないリファレンス変数を指定した場合
  • 存在しないプロパティを指定した場合
  • 存在しないメソッドを指定した場合
  • プロパティがnullを返す場合
  • メソッドがnullを返す場合
  • メソッドの返り値がvoidの場合

これを回避するために用いられるのが沈黙表記です。沈黙表記ではリファレンスの「$」の直後に「!」を記述します。沈黙表記を使用した場合、上記のような場合でもリファレンス文字列ではなく空文字が出力されます。沈黙表記は通常表記と正式表記の両方で使用可能です。

沈黙表記の例

$flow.email    ##通常表記
$!flow.email   ##沈黙表記
$!{flow.email} ##正式表記 かつ 沈黙表記

#*
実際には$flowのプロパティはnullの代わりに空文字を返すので、
あまり沈黙表記を使用する必要はありません。
*#

2.4. コメント

前節の例で「##」「#* ~ *#」という部分がありますが、これはVelocityのコメントです。テンプレート内に記述されていても出力結果には含まれません。

「##」以降の部分は1行コメントに、「#* ~ *#」で括られた部分はその範囲がコメントになります。

コメントの例

このテキストは表示されます。 ## このテキストは表示されません。
このテキストは表示されます。
このテキストは表示されます。 #* このテキストは、複数行コメントの一部
なので表示されません。このテキストも表示されません。
このテキストもまだ表示されません。*# このテキストはコメントの外側
なので表示されます。
## このテキストは表示されません。

2.5. リファレンスとJavaの関係

Velocityを使う上ではJavaの知識は必要ありませんが、Javaの知識がある人にとってはそちらから理解した方がわかりやすいので、ここでリファレンスとJavaの関係について説明を補足しておきます。

リファレンス変数に設定されているオブジェクトは実はJavaのオブジェクトそのものです。 つまりリファレンスのメソッドとは設定されているJavaクラスのpublicメソッドそのものです。

ではプロパティとは何かというと、これは次のルールに従って実行されるメソッドの返り値です。

  1. getXXXX()メソッドとして定義されたメソッドの返り値
    プロパティ名に対応するgetterメソッドがある場合、その返り値がプロパティ値となります。
  2. get(String propname) または get(Object propname)という名前のメソッドの返り値
    StringまたはObjectの単一引数をとる「get」という名前のメソッドがある場合そのメソッドにプロパティ名を渡した返り値がプロパティ値となります。

例えばオブジェクトに「String getName()」というメソッドが定義されている場合、Velocityでは「$obj.Name」「$obj.getName()」のどちらの表記も使用できますが、この場合はプロパティを使用することが推奨されており、この文書でもプロパティとして扱っています。

メソッドまたはプロパティの返り値のオブジェクトは何でも構いません。Velocityは返り値のオブジェクトのtoString()を出力テキストとして使用します。

後述する #if や #foreach などの指示子と組み合わせるとVelocity内で自由度の高いプログラミングを行うことも可能です。

$flow.StaffMail.strValue().toLowerCase() ##文字列の小文字化
#set($array = $flow.var1.strValue().split(","))
##フロー変数をカンマ区切りで配列化

逆から言えば自作の拡張クラスを作成してリファレンス変数に割り当てる場合は、このルールに従ってプロパティとメソッドを設計します。

3. 組込リファレンス その1

ここでは変数を中心にフローの組込リファレンスの詳細を説明していきます。入力ストリームを表す「$in」とユーティリティについては指示子の説明の後に扱います。

3.1. $flow - フロー変数

「$flow」はフロー変数を表すリファレンスです。デザイナーで定義したフロー変数がプロパティとして参照できます。

フロー変数の変数名として日本語などリファレンスで使用できない文字を使用している場合は以下のようにgetメソッドを使用して参照します。

$flow.get("変数1")

フロー変数参照の返り値はValueクラスのオブジェクトです。 ValueクラスはASTERIA内でデータを扱う基本的なラッパークラスであり、変数やレコードのフィールドデータなどほとんどのデータはこのクラスでラップされます。

Valueクラスの代表的なメソッドを以下に示します。

Valueクラスのメソッド
メソッド 引数 返り値 説明
strValue() なし String String型としての値
intValue() なし int Integer型としての値
longValue() なし long Integer型としての値
doubleValue() なし double Double型としての値
decimalValue() なし BigDecimal Decimal型としての値
dateValue() なし Date DateTime型としての値
booleanValue() なし boolean Boolean型としての値
byteValue() なし byte[] Binary型としての値
isNull() なし boolean 値がnullの場合にTrueを返します
toString() なし String strValue()と同じです

フロー変数にはデータ型がありますが、そのデータ型に関わらず上記のメソッドでは自動的に型変換が行われます。(String型の変数であっても内容が数値を表す文字列であれば、intValue()メソッドでそれをint型の数値として取得できます。ただし、内容が数値でない場合は「0」が返ります。)

strValue()やintValue()などの各種メソッドは値がnullの場合でもnullを返すことはありません。値がnullの場合はstrValue()メソッドは空文字を返し、intValue()メソッドは0を返します。nullと空文字を区別する必要がある場合はisNull()メソッドを使用します。

ValueクラスのtoString()メソッドはstrValue()を返すので「$flow.var1」のような記述も指定のフロー変数が存在する限り結果がnullとなることはありません。したがって、指定のフロー変数が存在する限り出力結果に「$flow.var1」という文字列がそのまま出力されることはありません。

テンプレート内に値を埋め込むだけであればこれらのメソッドを使用する必要はありませんが、文字列を他のリファレンス変数に代入する場合や数値の演算を行う場合には必要になります。

また、「$flow」自体に定義されているメソッドは以下の2つのみです。

$flowオブジェクトのメソッド
メソッド 引数 返り値 説明
get() String Value 変数名を指定してフロー変数を取得
toString() なし String フロー変数の一覧を返す

toStringメソッドが定義されているのでテンプレート内に「$flow」とだけ記述した場合はフロー変数の一覧が出力されます。

3.2. $local - ローカル変数

「$local」はVelocityコンポーネントの「ローカル変数」タブで定義した変数を参照するリファレンスです。フロー変数がフロー内すべてに共通する変数であるのに対しローカル変数はそのテンプレート内だけで使用する変数です。

使用方法や注意点は「$flow」と同じです。

$localオブジェクトのメソッド
メソッド 引数 返り値 説明
get() String Value 変数名を指定してローカル変数を取得
toString() なし String ローカル変数の一覧を返す

ローカル変数の例

$local.var1
$local.get("変数1")

3.3. $system - システム変数

「$system」はシステム変数を参照するリファレンスです。使用方法や注意点は「$flow」や「$local」と同じです。

$systemオブジェクトのメソッド
メソッド 引数 返り値 説明
get() String Value 変数名を指定してシステム変数を取得
toString() なし String システム変数の一覧を返す

システム変数として使用できるものに何があるかはフローサービスマニュアルの「システム変数」を参照してください。

システム変数の参照で使用できるのは英語表記のみです。日本語表記は使用できません。すべてのシステム変数はプロパティとして参照できます。

比較的よく使用するシステム変数にRequestURL(HTTPリクエストのURL)があります。HTMLフォームのactionに指定しておけば自分自身に対するリクエストとなります。あとにサンプルがありますが、検索条件と検索結果を同一ページに表示する画面を作成する場合などに便利です。

<form action="$system.RequestURL" method="post">
...
</form>

またWebから動作するフローでエラーが発生した場合に表示するページの中にExceptionDetail(エラー詳細)を埋めておくと原因究明が容易になることがあります。

<html>
<body>
<p>
エラーが発生しました
</p>

...

<!--
##HTMLのコメント内に埋めておくことで一般ユーザーの目には触れさせず
##ソースを表示した場合にのみエラー詳細を表示することができます。
$system.ExceptionDetail
-->
</body>
</html>

3.4. $exvar - 外部変数セット

「$exvar」は外部変数セットを参照するリファレンスです。フロー上に配置した外部変数セットを参照することができます。

外部変数セットは複数配置できるためフロー変数などに比べてリファレンスの表記が1階層が深くなります。最初に外部変数セット名を指定して次に変数名を指定します。外部変数セット名または変数名に日本語などのリファレンスで使用できない文字が使われている場合はgetメソッドを使用します。外部変数の種別(定数、リクエスト変数、セッション変数、アプリケーション変数)には関係なくすべて同じ指定方法で参照できます。

$exvarオブジェクトのメソッド
メソッド 引数 返り値 説明
get() String ExternalVariable 外部変数セット名を指定して外部変数セットを取得
ExternalVariablesオブジェクトのメソッド
メソッド 引数 返り値 説明
get() String Value 変数名を指定して外部変数セット内の変数を取得

外部変数セットの例

$exvar.Exvar1.var1
$exvar.get("外部変数セット1").var2
$exvar.get("外部変数セット1").get("変数3")

3.5. $encoding - 出力エンコーディング

「$encoding」はVelocityコンポーネントの出力ストリーム定義で指定したエンコーディング名の文字列(Stringオブジェクト)です。主に生成するHTMLのmetaタグでcharsetを指定する場合に使用します。

<html>
<head>
  <meta http-equiv="content-type" 
           content="text/html; charset=$encoding" />
</head>
...
</html>

4. 指示子

指示子とはVelocityにおける処理命令のことで「#」で始まるキーワードで表現されます。「#if」「#foreach」といった指示子を使用することでテンプレートの中に分岐や繰り返しといったロジックを組み込むことができます。

4.1. #set

「#set」はリファレンス変数に対して値を代入する指示子です。代入の左辺はリファレンス変数となり右辺には以下のいずれかが使用できます。

  • リファレンス(リファレンス変数、プロパティ、メソッド)
  • 文字列リテラル
  • 数値
  • 配列
  • 範囲(2つの整数間にある整数の配列)
  • 真偽値(true/false)

#setの例

#set ($str1 = $flow.var1.strValue()) ##フロー変数の文字列(String)
#set ($str2 = "aaa")                 ##文字列リテラル
#set ($num1 = $flow.var2.intValue()) ##フロー変巣の数値(int)
#set ($num2 = 123)                   ##数値
#set ($num3 = $num2 + 123)           ##数値演算
#set ($arr2 = ["一", "二", "三"]     ##配列
#set ($arr3 = [2000..2010])          ##範囲
#set ($flag = false)                 ##真偽値
#set ($arr1 = $flow.var3.split(",")) ##Stringのsplit関数の返り値(配列)

4.1.1. リファレンス

「#set」でリファレンスを代入する場合は、そのリファレンスが表すオブジェクトへの参照がリファレンス変数に代入されます。

#set ($var1 = $flow.var1)            ##「$var1」はValueオブジェクト
#set ($var2 = $flow.var1.strValue()  ##「$var2」はStringオブジェクト

4.1.2. 文字列リテラル

「#set」で文字列リテラルを使用する場合、文字列は二重引用符「"」または単一引用符「'」で括ります。

どちらを使用した場合もリファレンス変数の内容はStringオブジェクトになりますが二重引用符「"」を使用した場合は、引用符内のリファレンスがパースされるという違いがあります。

#set($str1 = "AAA")    ##二重引用符を使用。「AAA」をstr1に代入
#set($str2 = 'あああ') ##単一引用符を使用。
                       ##リファレンスがない場合はどちらでも同じ

#set($str3 = "str1は「$str1」でした") ##文字列中の「$str1」は変換される
#set($str4 = '変数名は「$str1」です') ##「$str1」はそのまま出力される

##文字列の連結する場合ははリファレンスを連続して記述
#set($str5 = "str1とstr2を連結「$str1$str2」") 

4.1.3. 数値

「#set」で数値を使用する場合、簡単な演算を行うことが可能です。

演算で使用できるのは整数(Integer)のみです。Valueクラスには長整数(Long)を返すlongValue()メソッドや浮動小数を返すdoubleValue()メソッドがありますが、それらを用いての演算はできません。

#set ($num1 = $flow.num1.intValue() + 5)                     ##加算
#set ($num2 = 20 - $flow.num1.intValue())                    ##減算
#set ($num3 = $flow.num1.intValue() * $flow.num2.intValue()) ##乗算
#set ($num4 = $flow.num1.intValue() / 5) ##除算。結果は整数
#set ($num5 = $flow.num1.intValue() % 5) ##剰余。除算のあまり

##括弧を使用して演算順序の制御もできる
#set ($num7 = 10)
#set ($num8 = $num7 + 5 * 10)   ##結果は「60」
#set ($num9 = ($num7 + 5) * 10) ##結果は「150」

4.1.4. 配列

配列を使用する場合、「[]」内に配列要素をカンマ区切りで配列要素を指定します。配列要素にリファレンスを指定することもできます。

#set ($arr1 = ["one", "two", "three"])
#set ($arr2 = [$flow.str1.strValue(), $flow.str2.strValue()]

配列の主なメソッドを以下にしめします。

配列オブジェクトのメソッド
メソッド 引数 返り値 説明
get() int Object 指定のインデックスに対応する配列要素を返します
size() なし int 配列の要素数を返します
indexOf() Object int 指定のObjectが配列要素に含まれている場合のインデックスを返します
contains() Object boolean 指定のObjectが配列要素に含まれているかどうかを返します

配列の実体は「java.util.ArrayList」クラスです。

4.1.5. 範囲

範囲は2つの整数間にある数値を配列化する記述方法です。主に後述の「#foreach」と組み合わせて回数を指定してループする場合に用いられます。数値の指定にリファレンスを指定することもできます。

#set ($arr1 = [1..10]) ##「1」から「10」までを要素とする配列
#set ($arr2 = [$flow.num1.intValue()..$flow.num2.intValue()]

#set ($arr3 = [10..1] ## 大きい数字から小さい数字の指定もOK

範囲の指定で先に大きい数字が指定された場合は、単純にカウントダウンしながら配列が作成されます。

4.1.6. 真偽値

真偽値は「true」または「false」のいずれかです。 主に後述の「#if」と組み合わせて用いられます。

#set ($flag1 = true)
#set ($flag2 = $flow.var1.booleanValue())

4.1.7. nullについて

「#set」でリファレンス変数にnullを代入することはできません。右辺の評価結果がnullの場合は単純に無視されて、元の値がそのまま維持されます。

またnullに対するプロパティやメソッドの実行も無視されるだけでエラーとはなりません。

#set ($var1 = "aaa")      ##文字列の代入
var1の値は「$var1」です。 ##この行の出力は「aaa」

##フロー変数「var1」が定義されていないとする
#set ($var1 = $flow.var1.strValue()) ##この行は無視される
var1の値は「$var1」です。 ##この行の出力も「aaa」

このことはループの中で繰り返し同じ変数を使用する場合に特に注意が必要です。

4.2. #if

「#if」指示子を使用すると条件に一致する場合のみ出力されるテンプレートを記述することができます。「#if」はその区間の終了をしめす「#end」と必ず対にする必要があります。

#if ($flow.var1.strValue() == "test")
この部分はフロー変数「var1」の値が「test」の場合だけ出力されます。
#end

「#else」を組み合わせることで条件に一致しない場合にのみ出力されるテンプレートを記述することもできます。また、「#elseif」を使用して複数の条件を組み合わせることも可能です。

#if ($flow.var1.intValue() == 1)
フロー変数var1は「1」です。
#elseif ($flow.var1.intValue() == 2)
フロー変数var1は「2」です。
#elseif ($flow.var1.intValue() == 3)
フロー変数var1は「3」です。
#else
フロー変数var1は不明です。
#end

ひとつの「#if」ブロック内に「#elseif」はいくつでも記述することができますが、「#else」は最後にひとつだけ記述することができます。条件は上から順に評価されていき、一度条件が一致するとそれ以降の条件式は評価されません。

4.2.1. 条件の評価方法

条件がリファレンスの場合以下のように判定されます。

  • リファレンスの表すオブジェクトが真偽値の場合、それがtrueであれば一致
  • それ以外の場合はオブジェクトがnullでなければ一致
#set ($flag1 = true)
#set ($flag2 = false)
#set ($obj1 = "hoge")

#if ($flag1) 
flag1はtrueなので表示される
#end
#if ($flag2) 
flag2はfalseなので表示されない
#end
#if ($obj1) 
obj1はnullでないので表示される
#end
#if ($obj2) 
obj2は未定義なので表示されない
#end
#if ($flow.var1.booleanValue()) 
フロー変数var1がtrueならば表示される
falseの場合や未定義の場合は表示されない
#end

「==」を使用して値が等しいかどうかを判定することもできます。この場合両辺は同種のオブジェクトである必要があります。つまりフロー変数を文字列や数値と比較する場合にはそれぞれstrValue()、intValue()メソッドを使用する必要があります。

#if ($flow.var1 == $flow.var2)
フロー変数var1とvar2が等しいかどうかを判定
#end
#if ($flow.var3.strValue() == "aaa")
フロー変数var3が文字列「aaa」と等しいかどうかを判定
ValueとStringの比較なのでValueをStringにする
#end
#if ($flow.var4.intValue() == 5)
フロー変数var4が数値「5」と等しいかどうかを判定
Valueとintの比較なのでValueをintにする
#end

#set ($temp = "aaa")
#if ($flow.var5.strValue() == $temp)
フロー変数var5がリファレンス変数tempと等しいかどうかを判定
ValueとStringの比較なのでValueをStringにする
#end

数値の比較の場合は「>」「<」「>=」「<=」が使用できます。

  • m > n : mはnより大きい
  • m < n : mはnより小さい
  • m >= n : mはn以上
  • m <= n : mはn以下
#if ($flow.var1.intValue() < 10)
var1は10より小さい
#elseif ($flow.var1.intValue() > 100)
var1は10より大きい
#end

「&&」「||」を使用して複数の条件を組み合わせたり、「!」を使用して条件を反転させることもできます。

  • A && B : AとBの両方の条件に一致
  • A || B : AとBいずれかの条件に一致
  • !A : Aの結果の逆
#if ($flow.var1.intValue < 10 || $flow.var1.intValue() > 100)
フロー変数var1が10より小さいか100より大きい場合
#end

#if (!$temp)
リファレンス変数tempがfalseかnull(未定義)の場合
#end

4.3. #foreach

「#foreach 」指示子はループを処理するために使用します。ループブロックの終わりをしめす「#end」と対にして使用します。構文は次のようになります。

#foreach (<リファレンス変数> in <リファレンスまたは配列>
...
#end

「in」の前にはループ内でコレクションまたは配列の要素を受けるリファレンス変数を置きます。 「in」の後ろには以下ののいずれかが入ります。

  • コレクション(java.util.Collectionの実装)を返すリファレンス
  • 配列(範囲を含む)

もっとも典型的な #foreach の使用例はCSVなどの入力ストリームに対してレコードごとにループして処理を行うケースです。

<table>
<tr>
	<th>フィールド1</th>
	<th>フィールド2</th>
	<th>フィールド3</th>
</tr>
#foreach ($r in $in.records)
<tr>
	<td>$r.field1</td>
	<td>$r.field2</td>
	<td>$r.field3</td>
</tr>
#end
</table>

リファレンス変数「$r」で一行分のレコードを受けて、#foreachブロック内の処理をレコードの行数回繰り返します。

ほとんどの場合「in」の後ろにはリファレンスが来ますが配列や範囲を直接指定することもできます。範囲を指定すること回数を決めてのループを行うことができます。

##配列を使用したループ
#foreach ($name in ["佐藤", "鈴木", "田中"])
$nameさんが来ました。
#end

##範囲を指定したループ
#foreach ($idx in [1..10])
...
#end

4.4. #includeと#parse

「#include」と「#parse」はいずれも外部ファイルをテンプレート内に取り込むための指示子です。Velocityコンポーネントのプロパティで「テンプレートの指定方法」プロパティが「ファイル」となっている場合のみ使用でき「直接入力」の場合は使用できません。

「#parse」では外部ファイル内のリファレンスや指示子が解釈されて変換されるのに対し、「#include」では単純にテキストがそのまま読み込まれます。

ファイルの指定はVelocityコンポーネントを使用しているASTERIAユーザーのホームディレクトリからの相対パスで行います。テンプレートファイル位置からの相対パスではないので注意が必要です。絶対パスを使用したり、「..」を使用してホームディレクトリ以外の階層にあるファイルを参照することはできません。

ファイルの指定は通常文字列で指定しますが、リファレンスで指定して動的に取り込むファイルを変更することもできます。

#parse ("vm/header.vm")
#include ($flow.includeFilename.strValue())

4.5. #macro

「#macro」はマクロを定義する指示子です。テンプレート内で頻繁に行われる処理をマクロとして定義しておけば名前を指定してそのマクロを呼び出すことで同じ処理を繰り返し記述することを避けられます。

「#macro」の定義では最初にマクロ名を、それに続けてスペース区切りで引数となるリファレンス変数名のリストを記述します。引数は0個以上の複数定義することができます。「#if」や「#foreach」と同じくマクロブロックの終わりに「#end」を使用します

次の例は引数がnullか空文字の場合に代替文字として「&nbsp;」を出力するマクロです。HTMLのtableでは空文字の場合に枠線が表示されないのでそれを避けるために使用できます。

#macro(print $ref)
#if (!$ref || $ref.toString().length() == 0)
&nbsp;
#else
$ref
#end
#end

呼び出し側では「#」に続けてマクロ名を記述し、「()」内にスペース区切りで引数リストを指定します。引数の数が一致していない場合はマクロは無視されます。

#print ("hoge") ##出力は「hoge」
#print ("")     ##出力は「&nbsp;」
#print ($var1)  ##var1が未定義か空文字の場合は「&nbsp;」
#print ($var1 "hoge") ##引数の数が一致しないので無視される

5. エスケープ

リファレンス変数や指示子を意図的にそのまま出力させたい場合は「\」を使用してエスケープすることができます。

\$flow.var1
\#set ($hoge = "aaa")

6. 組込リファレンス その2

ここでは入力ストリームを扱うための組込リファレンスとユーティリティについて説明します。

6.1. $in - 入力ストリーム

「$in」は入力ストリームを扱うためのリファレンスです。「$in」の実体は複数の入力ストリームを扱うコレクションです。

Velocityコンポーネントには複数のコンポーネントからの入力を差し込むことができます。これにより例えば社員一覧と部署一覧をそれぞれRDBGetコンポーネントで取得してその両方をVelocityコンポーネントでまとめてひとつのHTMLページを生成するといった処理が可能になります。

「$in」では複数のストリーム群の中からひとつのストリームを取得するためのメソッドが定義されています。

$inオブジェクトのメソッド
メソッド 引数 返り値 説明
array() int Stream インデックスを指定して入力ストリームを取得
インデックスはVelocityコンポーネントへの 入力順序の0ベースインデックスです
array() String Stream コンポーネント名またはリンク名を指定して入力ストリームを取得
size() なし int 入力ストリームの数を取得
$in.array(0).text()

#foreach ($in.array("RDBGet1").records)
...
#end

ただし、実際にVelocityコンポーネントに複数の入力ストリームが差し込まれることはまれで、ほとんどの場合入力ストリームはひとつしかありません。このため次節で説明するStreamオブジェクトのプロパティ/メソッドはすべて$inオブジェクトで再定義されて最初のストリームにフォワードされています。

Javaの疑似コードで書くと以下のようになります。

/** プロパティの取得をストリームにフォワード */
public Object get(String name) {
    return array(0).get(name);
}

/** テキストの取得をストリームにフォワード */
public String text() {
    return array(0).text();
}

...

実質的には$in自体が最初に入力されたStreamオブジェクトであると考えて差し支えありません。

6.2. Stream

Streamは$inまたは$in.array(0)などで取得した入力ストリームを表すオブジェクトです。

Streamでは入力ストリームを扱うためのプロパティ/メソッドが定義されています。

Streamオブジェクトのプロパティ
プロパティ 返り値 説明
records Collection #foreachでレコード単位でループさせるためのRecordオブジェクトのコレクションを返します
doc Document ストリームがXMLの場合にJDOMのDocumentオブジェクトを返します
<フィールド名> Value 最初のレコードのフィールド値を返します
Streamオブジェクトのメソッド
メソッド 引数 返り値 説明
record() int Record インデックスを指定してレコードをを取得します
インデックスは0ベースインデックスです
name() int String インデックスを指定してフィールド名を取得します
インデックスは0ベースインデックスです
text() なし String ストリーム全体を文字列で返します
toString() なし String text()と同じです
size() なし int レコード数を返します
variable() String Value 名前を指定してストリーム変数を返します
field() String Value 名前を指定して最初のレコードのフィールド値を取得します
field() int Value インデックスを指定して最初のレコードのフィールド値を取得します
インデックスは0ベースインデックスです
get() String Value field(String)と同じです

入力ストリームがRecordやCSVの場合には主にrecordsプロパティを使用して各レコードをループで処理します。

入力ストリームがXMLの場合はJDOMのDocumentを取得してそのメソッドや後述のXPathユーティリティを使用して各要素にアクセスできます。

フィールド名を指定して最初のレコードのフィールド値を取得することができます。入力ストリームがParameterListの場合「$in.field1」のように$inから直接フィールド値を取得できるので便利です。

6.3. Record

Recordでは1行分のレコードを扱うためのプロパティ/メソッドが定義されています。

Recordオブジェクトのプロパティ
プロパティ 返り値 説明
fields Collection #foreachでフィールド単位でループさせるためのValueオブジェクトのコレクションを返します
No int レコードの行番号(0ベース)を返します
<フィールド名> Value フィールド名に対応するフィールド値を返します
Recordオブジェクトのメソッド
メソッド 引数 返り値 説明
name() int String インデックスを指定してフィールド名を取得します
インデックスは0ベースインデックスです
size() なし int フィールド数を返します
field() String Value 名前を指定してフィールド値を取得します
field() int Value インデックスを指定してフィールド値を取得します
インデックスは0ベースインデックスです
get() String Value field(String)と同じです

レコード形式のストリームをHTMLのtableで表示させる汎用的なテンプレートの例を以下にしめします。

<table>
    <tr>
##ヘッダとしてフィールド名を出力
#set ($fieldCount = $in.record(0).size() - 1)
#foreach($idx in [0..$fieldCount])
        <th>$in.name($idx)</th>
#end
    </tr>
##レコードとフィールドで二重ループして全データを出力
#foreach ($r in $in.records)
    <tr>
#foreach ($v in $r.fields)
        <td>$v</td>
#end
    </tr>
#end
</table>

6.4. JDOM

入力ストリームがXMLの場合はStreamオブジェクトのdocプロパティからJDOMのDocumentオブジェクトが取得できます。 JDOMはXMLを扱うためのAPIの一種で、通常のDOMとは異なり子要素をコレクションとして扱えるという特徴があります。このためVelocityとの連携では要素単位でループをまわして処理を行うことが可能です。

以下にJDOMクラスの主なプロパティとメソッドをしめします。名前空間のあるXMLを扱う場合などには、ここに記した以外のメソッドが必要となるので正確なメソッドの一覧を知りたい方はJDOMのJavaDocを参照してください。

Documentオブジェクトのプロパティ
プロパティ 返り値 説明
RootElement Element 文書要素を返します
Elementオブジェクトのプロパティ
プロパティ 返り値 説明
Name String 要素名(ローカルネーム)を返します
Text String 要素内容を返します
Children List 子要素のリストを返します
#foreachでループさせることができます
Elementオブジェクトのメソッド
メソッド 引数 返り値 説明
getAttributeValue() String String 属性名を指定して属性値を取得します
getChild() String Element 要素名を指定しその名前を持つ最初の要素を返します
getChildren() String List 要素名を指定しその名前を持つ要素をListで返します
#foreachでループさせることができます

以下は入力データのXMLをHTMLのtableとして出力する例です。

入力データ
------
    
この記事は役に立ちましたか?
0人中0人がこの記事が役に立ったと言っています
    キーワード:
  • パイプラインサービス
  • フローサービス
  • 技術資料
他にご質問がございましたら、リクエストを送信してください

このセクションの記事

他のキーワードで検索する