プログラムの記述
引き続き、プログラムを記述していきます。プログラムでは、Velocity
クラスとVelocityContext
クラスを利用します。また、NVelocity固有の例外をハンドリングするため、例外クラスも利用します。
クラス名 | 名前空間 | 説明 |
Velocity | NVelocity.App | NVelocity本体。テンプレートとコンテキストのマージを実行するクラス |
VelocityContext | NVelocity | テンプレートから参照できるコンテキスト |
ResourceNotFoundException | NVelocity.Exception | テンプレートファイルが見つからない場合に発生する例外 |
ParseErrorException | NVelocity.Exception | テンプレートの内容が不正な場合に発生する例外 |
そのため、フォームの一番上で次のようなusing設定を行っておきます。
using NVelocity; using NVelocity.App; using NVelocity.Exception;
プログラムの全体像
btnMerge
ボタンがクリックされた場合、次のようにNVelocityを利用します。詳細については、この後で個別に説明していきますので、ここでは全体の雰囲気をつかんでもらえれば結構です。
//NVelocityの初期化 Velocity.Init(); //コンテキストの設定 VelocityContext ctx = new VelocityContext(); //名前をセット ctx.Put("name", this.txtName.Text); //住所をセット ctx.Put("address", this.txtAddress.Text); //備考をセット ctx.Put("remarks", this.txtRemarks.Text); //注文をセット ArrayList list = new ArrayList(); foreach(string item in this.lstOrder.SelectedItems) { list.Add(item); } ctx.Put("orderlist",list); //配送希望日をセット ctx.Put("senddate", this.dtpSendDate); try { //結果を格納するStringWriter System.IO.StringWriter resultWriter = new System.IO.StringWriter(); //Shift-JISのテンプレートファイルを読み込み、コンテキストとマージ Velocity.MergeTemplate("../../mail.vm", "Shift-JIS",ctx, resultWriter); //結果を画面に表示 this.txtResult.Text = resultWriter.GetStringBuilder().ToString(); } catch(ResourceNotFoundException ex) { MessageBox.Show("テンプレートファイルが見つかりませんでした", "エラー",MessageBoxButtons.OK,MessageBoxIcon.Warning); } catch(ParseErrorException ex) { MessageBox.Show("テンプレートの解析時にエラーが発生しました", "エラー",MessageBoxButtons.OK,MessageBoxIcon.Warning); }
プログラムの詳細解説
NVelocityの初期化
最初に、Init
メソッドによってNVelocityの初期化を行います。NVelocityを利用するためにはこのInit
メソッドの呼び出しが必須となります。
Velocity.Init();
引数なしでInit
メソッドを実行した場合には、実行ファイルと同じフォルダにある「NVelocity.properties」ファイルが読み出されます。ただし「NVelocity.properties」ファイルが存在しなくてもエラーにはならず、デフォルト値によってNVelocityは初期化されます。
初期設定ファイルには、次のようにデフォルトエンコーディングなどを指定できます。
#ファイル読み込み時のデフォルトエンコード input.encoding=Shift-JIS #ファイル書き出し時のデフォルトエンコード output.encoding=Shift-JIS # foreach内で使用可能なカウンタ変数名 directive.foreach.counter.name = velocityCount # foreach内で使用可能なカウンタ変数名の初期値 directive.foreach.counter.initial.value = 1
なお、Init
メソッドの引数にプロパティファイル名を指定することもできます。
コンテキスト設定
コンテキストはテンプレートファイルから参照できる領域にあたります。テンプレートから利用する変数をPut
メソッドによって追加していきます。
//コンテキストの設定 VelocityContext ctx = new VelocityContext(); //名前をセット ctx.Put("name", this.txtName.Text); //住所をセット ctx.Put("address", this.txtAddress.Text); //備考をセット ctx.Put("remarks", this.txtRemarks.Text); //注文をセット ArrayList list = new ArrayList(); foreach(string item in this.lstOrder.SelectedItems) { list.Add(item); } ctx.Put("orderlist",list); //配送希望日をセット ctx.Put("senddate", this.dtpSendDate);
ここでは、VelocityContext
クラスをインスタンス化し、Put
メソッドによってキーと値を設定しています。基本的にコンテキストには文字列を格納しますが、オブジェクトを格納することも可能です。ここでは文字列、ArrayList、DateTimePickerコントロールをコンテキストに設定しています。
テンプレートとコンテキストのマージ
最後にテンプレートとコンテキストのマージ(合併)を行います。マージを行った結果はWriterに格納されるため、StringWriterを生成した後で、Velocity
クラスのMergeTemplate
メソッドを呼び出します。
//結果を格納するStringWriter System.IO.StringWriter resultWriter = new System.IO.StringWriter(); //Shift-JISのテンプレートファイルを読み込み、コンテキストとマージ Velocity.MergeTemplate("../../mail.vm", "Shift-JIS",ctx, resultWriter); //結果を画面に表示 this.txtResult.Text = resultWriter.GetStringBuilder().ToString();
MergeTemplate
メソッドでは次の4つの引数を指定します。
- テンプレートファイル名
- テンプレートファイルの文字コード(省略時/初期設定ファイル未設定時は西欧諸語の「ISO-8859-1」が適用)
- コンテキスト
- 結果を格納するWriter
MergeTemplate
メソッドの実行後に、Writerからマージされたアウトプットを取り出すことができます。ここでは、StringWriterを使っていますが、StreamWriterなどを利用すればファイルに保存することもできるでしょう。
Exceptionについて
NVelocityでは、テンプレートファイルのマージ処理において例外が発生する可能性があるため(テンプレートを事前にコンパイルしてソースをチェックすることができないため)、確実にエラーハンドリングを行う必要があります。
try{ Velocity.MergeTemplate("../../mail.vm", "Shift-JIS",ctx, resultWriter); } catch(ResourceNotFoundException ex) { MessageBox.Show("テンプレートファイルが見つかりませんでした", "エラー",MessageBoxButtons.OK,MessageBoxIcon.Warning); Console.WriteLine( "■テンプレートファイルが見つかりませんでした\n\n" + ex.ToString()); } catch(ParseErrorException ex) { MessageBox.Show("テンプレートの解析時にエラーが発生しました", "エラー",MessageBoxButtons.OK,MessageBoxIcon.Warning); Console.WriteLine( "■テンプレートの解析時にエラーが発生しました\n\n" + ex.ToString()); }
テンプレートファイルが見つからないときに発生する「ResourceNotFoundException」と、テンプレートファイルの構文エラーで発生する「ParseErrorException」をハンドリングするように心掛けましょう。なお、コンテキストに設定されていない変数をテンプレートから参照した場合、エラーは発生せず変数名がそのまま表示されるだけなので注意してください。
以上でアプリケーションは完成です。プログラムを動かして、想定どおりメールの本文が生成されているか確認してみてください。
まとめ
最後に、NVelocityについてまとめます。
- NVelocityはテンプレートという雛形からテキストを生成できるテンプレートエンジンである。
- テンプレートはVTL(Velocity Template Language)という言語で記述する。
NVelocity
クラスとNVelocityContext
クラスを使ってプログラミングを行う。- テンプレートとプログラムで共有する値はコンテキスト(
NVelocityContext
クラス)に設定する。 NVelocity
クラスのMergeTemplate
メソッドを呼び出すと、テンプレートとコンテキストがマージされ、結果を出力することができる。
NVelocityの最新バージョンはまだ0.5ですが、既にMonoRailやNHibernateContribといったオープンソースプロダクトで利用されています。また、今後のシステム開発の選択肢の一つとして、テンプレートエンジンという考え方を理解しておくと良いのではないでしょうか。
参考資料
- NVelocity(SourceForge:英語)
- Castle Project(最新ソース:英語)
- Template merging with NVelocity and ASP.NET(NVelocityラッパークラスの紹介:英語)
- CSharp-Source.NET(C#のオープンソーステンプレートエンジン一覧:英語)
- SharpToolbox Code generation(コード生成プロダクト一覧:英語)
- JaJakarta Velocity-1.3.1 日本語ドキュメント注2
- Jakarta Velocityでテンプレートを変換しメールを送信する注2