基本的にテンプレート中の特定箇所をプログラマが与えたMapにしたがって置換した結果を得るものです。
テンプレートはHTMLエディッタ等でも基本的に不都合無く編集が行えるので、事務のおねーさんにだってOKっす。(注1)
以下の情報を渡すことでフォーマッティングを行います。
| 生成時 | 変換を行うテンプレートファイルとエンコーディング |
| format時 | 変換表となるMapインスタンス |
テンプレートファイルに以下のようにコマンド/キーを記述しておきます。
キーに対応するsubstitute(変換候補)オブジェクト群はMapとしてFormatterに与えます。
| コマンド(ignore case) | 書式 | 意味 |
|---|---|---|
| substitute # |
@#substitute key@ または@##key@ |
Map上のkeyに対応するvalueに置換。 keyがMap上に存在しない場合は無視される。 |
| exist〜endexist | @#exist key@〜 [@##key@]〜 @#endexist@ |
keyが存在すれば囲まれた範囲が評価される。 存在しなければ無視される。 |
| while〜endwhile | @#while key@〜@#endwhile@ | 囲まれた範囲をkeyに対応する値の個数だけ繰り返す。 値はMapの配列またはMapのListで無ければならない。 |
| if〜endif | @#if key = value1@〜@#endif@ @#if key != value2@〜@#endif@ |
キーの値に応じて評価される部分を変更する。 通常はexistで対応可能。 |
| foreach〜endforeach | @#foreach key@〜 [@##key@]〜 @#endforeach@ |
囲まれた範囲をkeyに対応する値の個数だけ繰り返す。 値はObject配列またはListでなければならない。 囲まれた範囲に一種類のkeyしか存在しないはこちらが手軽。 他の置換キーがあった場合は同じ値が繰り返し出力される。 |
@##key@
@## key @
@##
key
@
以下も同様です。(日本語もOK)@#if キーワード!=値@ @#ifキーワード!=値@ @#if キーワード != 値 @ @#if キーワード != 値 @
・・・foo@bar・・・ -> OK ・・・@#exist abc@@・・・ -> OK ・・・foo@@・・・ -> NG ・・・@#exist abc@@@・・・ -> NG ・・・foo@#bar・・・ -> NG ・・・foo@#exisy abc@・・・ -> NG ・・・@@#exist abc@・・・ -> NGエスケープされていない"@"の直後に"#"、"@"、"\"が現れた場合、TextFormatterは文法エラー(WrappedParseException)を発生させます。
・・・foo\@@・・・ ・・・foo\@#bar・・・ ・・・\@@#exist abc@・・・ ・・・@#exist abc@\@@・・・普通はこの問題が発生するようなtemplateにはならないとは思いますが・・・。
変換の実行は、以下のように行います。
import com.sk_jp.text.*;
:
TextFormatter formatter;
formatter = new TextFormatter("file.template", "Shift_JIS");
Map args = new HashMap();
args.put("key1", "value1");
args.put("key2", "value2");
String result = formatter.format(args);
// or formatter.format(args, writer);
以降でそれぞれのコマンド使用方法を具体的な例で説明します。
<html> <head> <title>@#substitute filetitle@</title> </head> <body> 今日の日付は@##date@です。 </body> </html>
与えるMapのインスタンス
| filetitle | "今日は" |
| contents | new Date() |
結果
<html> <head> <title>今日は</title> </head> <body> 今日の日付はTue Mar 14 08:35:31 JST 2000です。 </body> </html>
<html> @#exist stylesheeturl@ <meta http-equiv="Content-Style-Type" content="text/css" /> <link rel="stylesheet" href="@##stylesheeturl@" type="text/css" /> @#endexist@ <body> @#exist title@<h1>@##title@</h1>@#endexist@ : </body> </html>
与えるMapのインスタンス
| stylesheeturl | "/sample.css" |
結果
<html> <meta http-equiv="Content-Style-Type" content="text/css" /> <link rel="stylesheet" href="/sample.css" type="text/css" /> <body> : </body> </html>
"title"というキーに対応する値が無い場合は<h1>タグも出力されない
<html><body> <table><tbody> <tr><th>ヘッダ1</th><th>ヘッダ2</th></tr> @#while row@ <tr><td>@##column1@</td><td>@##column2@</td></tr> @#endwhile@ </tbody></table> </body></html>
与えるMapのインスタンス
| row | Mapインスタンスの配列またはMapの集合を格納したListインスタンス |
Mapの配列
|
|
|
結果
<html><body> <table><tbody> <tr><th>ヘッダ1</th><th>ヘッダ2</th></tr> <tr><td>列1-1</td><td>列2-1</td></tr> <tr><td>列1-2</td><td>列2-2</td></tr> <tr><td>列1-3</td><td>列2-3</td></tr> : </tbody></table> </body></html>
"row"というキーの値は繰り返される個数分のMapの集合となる。
もちろんそのマップには"column1""column2"というキーが存在する。
# こんなにMapインスタンスを多数生成してたら効率悪すぎか?
# しかし、キー名にindex付けを行うなどでは使いづらいし。
<html><body>
<h1>集計結果</h1>
@#while category@
<table>
<thead><caption>@##categorytitle@</caption></thead>
<tbody>
@#while item@
<tr><td>項目名</td><td>@##itemname@</td></tr>
@#while@
</tbody></table>
@#while@
</body></html>
与えるMapのインスタンス
| category | Mapインスタンスの配列またはMapの集合を格納したListインスタンス |
Mapの配列
|
|
|
上記のそれぞれの「Map配列」には、キー「itemname」に対応する値を持つMapの配列が格納。
結果
<html><body>
<h1>集計結果</h1>
<table>
<thead><caption>表1</caption></thead>
<tbody>
<tr><td>項目名</td><td>項目1</td></tr>
<tr><td>項目名</td><td>項目2</td></tr>
:
</tbody></table>
<table>
<thead><caption>表2</caption></thead>
<tbody>
<tr><td>項目名</td><td>項目1</td></tr>
<tr><td>項目名</td><td>項目2</td></tr>
:
</tbody></table>
<table>
<thead><caption>表3</caption></thead>
<tbody>
<tr><td>項目名</td><td>項目1</td></tr>
<tr><td>項目名</td><td>項目2</td></tr>
:
</tbody></table>
</body></html>
通常は@#exist name@ @#exist@で事足りる。ループ中でその項目ごとにフォーマットを変更できるようにしたい場合に用いる。
<html><body>
<h1>集計結果</h1>
@#while category@
@#if type=table>@
<h2>@## title@の選択数</h2>
<table><tbody>
@#while item@
<tr><td>項目名</td><td>@## itemname@</td></tr>
@#while@
</tbody></table>
@#endif@
@#if type=link@
<h2><a href="/servlets/listing.jsp?id=@## id@">
@## title@の一覧</a></h2>
@#endif@
@#endwhile@
</body></html>
与えるMapのインスタンス
| category | Mapインスタンスの配列またはMapの集合を格納したListインスタンス※ |
※:Mapの配列
|
|
|
※2:Mapの配列
|
|
結果(空白行は見やすくしているだけです)
<html><body>
<h1>集計結果</h1>
<h2>項目1の選択数</h2>
<table><tbody>
<tr><td>選択項目1</td><td>5</td></tr>
<tr><td>選択項目2</td><td>3</td></tr>
:
</tbody></table>
<h2><a href="/servlets/listing.jsp?id=2">項目2の一覧</a></h2>
<h2>項目3の選択数</h2>
<table><tbody>
<tr><td>選択項目1</td><td>14</td></tr>
<tr><td>選択項目2</td><td>8</td></tr>
:
</tbody></table>
:
</body></html>
<html><body> <table><tbody> <tr>@#while column@<th>@##head@</th>@#while@</tr> @#while row@<tr>@#while column@<td>@##body@</td>@#while@</tr>@#while@ </tbody></table> </body></html>
Mapのインスタンス
| column | Mapインスタンスの配列またはMapの集合を格納したListインスタンス |
| row | Mapインスタンスの配列またはMapの集合を格納したListインスタンス |
[row]の値であるMap配列
| column | Mapインスタンスの配列またはMapの集合を格納したListインスタンス |
[column]にはそれぞれ[head][body]というキーを持ったMapの配列が入る。
すみません例が悪かった。今はforeachが使えるのでもうちょっと簡潔になります。
結果
<html><body> <table><tbody> <tr><th>ヘッダ1</th><th>ヘッダ2</th><th>ヘッダ3</th></tr> <tr><td>ボディ1-1</td><td>ボディ2-1</td><td>ボディ3-1</td></tr> <tr><td>ボディ1-2</td><td>ボディ2-2</td><td>ボディ3-2</td></tr> <tr><td>ボディ1-3</td><td>ボディ2-3</td><td>ボディ3-3</td></tr> : </tbody></table> </body></html>