テンプレート・エンジン「StringTemplate.NET」を使う:連載:VBで実践! 外部コンポーネント活用術(2/2 ページ)
ひな型ファイルに埋め込まれたキーワードを置換するテンプレート・エンジンをVBで活用。ひな型に条件分岐なども記述できる。
テンプレート処理
これまでの説明では、テンプレート・ファイルを作成し、そこに属性を記述することで、テンプレートからテキスト・ファイルを生成できることを紹介しました。しかし、これだけの処理なら、テンプレート・エンジンを使わなくても実現は難しくありません。
ここからはもう少し踏み込んで、StringTemplateのさまざまな機能を利用した例を紹介します。
■繰り返し処理
HTMLファイルに限らず、テンプレートを使ったファイル生成が有用なのは、データベースの結果セットやXMLファイルといった、連続するデータを扱う場合です。
例えば次のような都道府県の一覧を生成したい場合、
<ul>
<li>北海道</li>
<li>青森県</li>
……
</ul>
StringTemplateでは次のようなテンプレートを記述します。
<ul>$names:{n|<li>$n$</li>}$</ul>
これを用いて上記のリストを生成するコードを次に示します。
Private Sub proc04()
Dim tmp As String = "<ul>$names:{n|<li>$n$</li>}$</ul>"
Dim st As New StringTemplate(tmp)
Dim dt As String() = {"北海道", "青森県", "岩手県"}
st.SetAttribute("names", dt)
Console.WriteLine(st)
End Sub
このテンプレートでは、「$names$」という属性に対して、属性にセットする配列の各要素に<li>タグを付加するように指示しています。テンプレートに含まれる「n」は、namesに含まれる配列要素(names(0)、names(1)、……)を表します(nには任意の文字が指定できます)。
これを実行すると、次の結果が得られます。
<ul>
<li>北海道</li>
<li>青森県</li>
<li>岩手県</li>
</ul>
■条件判断を行う
StringTemplateでは、テンプレート内で条件判断を行うことも可能です。条件判断を行うには、テンプレートに「$if$」「$else$」「$endof$」といったステートメントを記述します。
次に示すテンプレートでは、「x」が真なら「こんにちは $name$ さん」が、偽なら「さようなら$name$ さん」が出力されます。
$if(x)$
こんにちは $name$ さん
$else$
さようなら $name$ さん
$endif$
「$if(x)$」のxに対して真または偽を設定する場合もSetAttributeメソッドを使用します。属性に内容をセットする場合と同様に、次のように真偽値を設定できます。
st.SetAttribute("x", True)
st.SetAttribute("name", "岸本")
■1行ごとにテンプレートを変更する
テンプレートを複数利用することで、HTMLファイルの<table>タグ内の行の背景を交互に変更するような出力を得ることも可能です。これには次のリスト7のようなテンプレートを用意します。
ここでは、<table>タグ全体を出力する「base」、行の表示を行う「row1」と「row2」の3つのテンプレートを定義します。row1とrow2では<tr>タグに異なるセレクタ(evenあるいはodd)を記述しています。
テンプレート内に、さらに別のテンプレートを含める場合は、テンプレート名にカッコを付けて、メソッド呼び出しのように記述します。なお、テンプレート中の「$\n$」は、改行を表します。
group test;
base(rows) ::= <<
<table>
$rows:row1(),row2()$
</table>
>>
row1(val) ::= <<
<tr class="even"><td>$val$</td></tr>$\n$
>>
row2(val) ::= <<
<tr class="odd"><td>$val$</td></tr>$\n$
>>
baseテンプレートには、rows属性に対して、row1とrow2の2つのテンプレートを交互に呼び出すように記述しています。これによりrowsに配列がセットされた場合、最初の配列の要素に対してはrow1が、次の要素にはrow2が呼び出されるようになります。3番目の要素に対応するテンプレートはありませんので、再度row1が呼び出されます。これが繰り返されることで、1行ごとに背景色を変更する(ここではセレクタを変更しているだけですが)といったことが可能になります。
プログラム側では、次のようにSetAttributeメソッドでrowsに配列をセットします。
Private Sub proc05()
Dim grp As New StringTemplateGroup( _
New StreamReader("templates\\template03.st"), _
GetType(DefaultTemplateLexer))
Dim st As StringTemplate
Dim prefs As String() = {"北海道", "青森県", "岩手県"}
st = grp.GetInstanceOf("base")
st.SetAttribute("rows", prefs)
Console.WriteLine(st)
End Sub
アプリケーション側では処理に変わりはない。
これを実行すると、次のような結果が得られます。
<table>
<tr class="even"><td>北海道</td></tr>
<tr class="odd"><td>青森県</td></tr>
<tr class="even"><td>岩手県</td></tr>
</table>
見やすいよう改行を入れています。
■クラス/構造体を利用する
ここまでは、テンプレートに属性を1個だけ定義していましたが、実際には多数の属性をテンプレートに定義することになります。そういった場合は、StringTemplateのプロパティ機能を利用することで、属性とその内容を効率よくセットできるようになります。
StringTemplateにおけるプロパティとは、C#やVBなどのクラスにおけるプロパティと同じようなもので、属性名に「.」(ピリオド)を付加してプロパティを表します。プロパティを使うと、次のようなテンプレートが記述できます。
"$persons:{n|<tr><td>$n.Name$</td><td>$n.Email$</td></tr>}$"
ここではpersons属性に付加するプロパティとして、NameとEmailを使用しています。「n」はpersonsの配列要素に対応します。そして、「$n.Name$」と「$n.Email$」は、SetAttributeメソッドで指定したオブジェクトのNameプロパティとEmailプロパティを参照します。オブジェクトに対応するプロパティが存在しない場合は、同じ名前のPublicメンバを参照します。
Structure Person
Public Name As String
Public Email As String
Public Sub New(ByVal name As String, ByVal email As String)
Me.Name = name
Me.Email = email
End Sub
End Structure
Private Sub proc06()
Dim tpl As String = "<table>$\n$$persons:{n|<tr><td>$n.Name$</td><td>$n.Email$</td></tr>$\n$}$</table>"
Dim st As New StringTemplate(tpl)
Dim persons As New List(Of Person)()
persons.Add(New Person("Yusuke", "yusuke@foo.com"))
persons.Add(New Person("Taro", "taro@foo.com"))
st.SetAttribute("persons", persons)
Console.WriteLine(st)
End Sub
これを実行すると次のような結果が得られます。
<table>
<tr><td>Yusuke</td><td>yusuke@foo.com</td></tr>
<tr><td>Taro</td><td>taro@foo.com</td></tr>
</table>
見やすいように改行を入れています。
まとめ
非常に駆け足でしたが、StringTemplateで利用頻度が高いと思われる代表的な機能を紹介しました。HTMLファイルの生成が中心になりましたが、StringTemplateは非常に高機能で、ほかにもXMLファイルの作成やデータベースのレコード作成など、さまざまな用途に利用できます。
日本語のドキュメントがないのが残念ですが、ダウンロードしたZIPファイルに含まれるPDF形式のドキュメントに加えて、別でHtmlHelp形式のリファレンスも配布されています。
Copyright© Digital Advantage Corp. All Rights Reserved.