Kwartzリファレンスマニュアル
last update: $Date: 2005-04-30 10:56:26 +0900 (Sat, 30 Apr 2005) $
はじめに
このドキュメントは、Kwartzのリファレンスマニュアルです。 プレゼンテーション用言語「PL」、ディレクティブ、コマンドラインオプション、 設定オプションについて説明しています。
目次
プレゼンテーション用言語「PL」
PLとは、Kwartzにおいてプレゼンテーションロジックを記述するのに利用される言語です。 この章では、PLの書き方について説明します。
コメント
「/*
」と「*/
」で囲まれた範囲と、「//
」から行末まではコメントになります。
// ここはコメント /* ここもコメント */
文字列
文字列は「"..."
」または「'...'
」で表します。
前者には改行(Line Feed)「\n」と復改(Carriage Returen)「\r」とタブ(Tab)「\t」を含めることができます。
'foo bar' // 文字列 "foo bar\n" // 改行を含む文字列
真偽値、null
式の中で true
、false
、null
が使えます。
flag = obj == null ? true : false;
true
、false
、null
は各言語において次のように変換されます。
変換先言語 | true | false | null |
---|---|---|---|
PHP | TRUE | FALSE | NULL |
eRuby | true | false | nil |
JSP(JSTL) | true | false | null |
Velocity | true | false | - |
なおVelocityではnullやそれに類するキーワードがありません。 そのため、nullを含むPLプログラムをVelocityに変換するとエラーになります。 ただしnullとの比較を行う論理式は、nullを使わない式に変換されます。
PLプログラム:
flag = obj == null? true : false; if (expr != null) { print("expr is not null.\n"); } else { print("epxr is null.\n"); }
出力用スクリプト:
### for Velocity #if($obj) #set($flag = true) #else #set($flag = false) #end #if(! $expr) expr is not null. #else epxr is null. #end
変数
変数はアルファべットまたは「_」で始まり、アルファベットと数字と「_
」が連続したものです。
また変数には型がなく、変数宣言もする必要がありません(*1)。
- (*1)
- この性質から、PLまたはPL-Kwartzで書かれたプログラムを、変数に型のある言語や変数宣言が必要な言語に変換するのは困難です。
演算子
演算子には次のものが使用できます。基本的には、文字列用と数値用とで演算子を分けてはいません(*2)。
比較演算子 | == != < <= > >= |
論理演算子 | && || ! |
算術演算子 | + - * / % |
文字列の連結 | .+ |
条件演算子 | ?: |
文字列の連結演算子「.+
」は、eRubyでは「+
」に、PHPでは「.
」に、
JSTL1.1では関数fn:join()
に変換されます。
JSTL1.0では連結演算子がないので、トリッキーな方法で凌いでいます。
Velocityではエラーになります。
PLプログラム(PL):
filename = basename .+ '.plogic';
出力用スクリプト:
### for eRuby <% filename = basename + ".plogic" %> ### for PHP <?php $filename = $basename . ".plogic"; ?> ### for JSTL 1.1 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> <c:set var="filename" value="${fn:join(basename,'.plogic')}"/> ### for JSTL 1.0 <%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %> <c:set var="filename" value="${basename}${'.plogic'}"/>
条件演算子(3項演算子)はeRubyとPHPとJSTL1.1では使用できますが、JSTL1.0とVelocityでは使用できません。 そのため条件演算子を含む式は、JSTL1.0とVelocityではif文(JSTL1.0ならif文に相当する<c:choose>)に変換されます。
PLプログラム(PL):
color = ctr % 2 == 0 ? '#FFCCCC' : '#CCCCFF';
出力用スクリプト:
### for eRuby <% color = ctr % 2 == 0 ? "#FFCCCC" : "#CCCCFF" %> ### for PHP <?php $color = $ctr % 2 == 0 ? "#FFCCCC" : "#CCCCFF"; ?> ### for JSTL 1.1 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> <c:set var="color" value="${ctr % 2 eq 0 ? '#FFCCCC' : '#CCCCFF'}"/> ### for JSTL 1.0 <%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %> <c:choose><c:when test="${ctr % 2 eq 0}"> <c:set var="color" value="#FFCCCC"/> </c:when><c:otherwise> <c:set var="color" value="#CCCCFF"/> </c:otherwise></c:choose> ### for Velocity #if($ctr % 2 == 0) #set($color = "#FFCCCC") #else #set($color = "#CCCCFF") #end
- (*2)
- Perlのように文字列用と数値用とで演算子が異なる言語に対しては、Kwartzを対応させるのは困難です。
出力
出力は「print(...);
」で表します。
引数には任意の式を書くことができます。
PLプログラム:
print('foo', bar, "baz\n"); // 文字列と変数を出力
出力用スクリプト:
### for eRuby foo<%= bar %>baz ### for PHP foo<?php echo $bar; ?>baz ### for JSTL foo<c:out value="${bar}" escapeXml="false"/>baz ### for Velocity foo$!{bar}baz
自動サニタイズ機能を使用した場合は次のような出力になります。
### for eRuby foo<%= CGI::escapeHTML((bar).to_s) %>baz ### for PHP foo<?php echo htmlspecialchars($bar); ?>baz ### for JSTL foo<c:out value="${bar}"/>baz ### for Velocity foo$!esc.html($bar)baz
また自動サニタイズ機能を使用しても、条件演算子が返す値が文字列または数字である場合は、サニタイズされません。
PLプログラム:
// サニタイズされる print("<option ", condition ? var1 : var2, ">\n"); // サニタイズされない(必要がないから) print("<option ", condition ? 'selected' : '', ">\n");
出力用スクリプト:
### for eRuby <option <%= CGI::escapeHTML((condition ? var1 : var2).to_s) %>> <option <%= condition ? "selected" : "" %>> ### for PHP <option <?php echo htmlspecialchars($condition ? $var1 : $var2); ?>> <option <?php echo $condition ? "selected" : ""; ?>> ### for JSTL <option <c:out value="${condition ? var1 : var2}"/>> <option <c:out value="${condition ? 'selected' : ''}" escapeXml="false"/>>
「print(a .+ b .+ c);
」は「print(a); print(b); print(c);
」と展開されます。
これは、文字列の連結演算子「.+
」をサポートしていない一部の言語を考慮した仕様です。
代入
代入は「var = 100;
」のように行います。
また、「+=
」「-=
」「*=
」「/=
」「%=
」「.=
」も使用できます。
PLプログラム:
name = 'Foo'; // 文字列を代入 count += 1; // 値を1増やす str .+= '.txt'; // 文字列の末尾に追加
出力用スクリプト:
### for PHP <?php $name = "Foo"; ?> <?php $count += 1; ?> <?php $str .= ".txt"; ?> ### for eRuby <% name = "Foo" %> <% count += 1 %> <% str += ".txt" %> ### for JSTL 1.1 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> <c:set var="name" value="Foo"/> <c:set var="count" value="${count + 1}"/> <c:set var="str" value="${fn:join(str,'.txt')}"/> ### for JSTL 1.0 <%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %> <c:set var="name" value="Foo"/> <c:set var="count" value="${count + 1}"/> <c:set var="str" value="${str}${'.txt'}"/>
配列、ハッシュ
配列は「arr[expr]
」の形で参照できます。
ハッシュも同じ形で参照できます(*3)。
JSTLでは配列やハッシュの要素を参照することはできますが、配列やハッシュの要素に代入することはできません。
PLプログラム:
list[n] = 10; // n番目の要素に代入 print(list[i], "\n"); // i番目の要素を出力 hash['key'] = 'foo'; // ハッシュの要素に代入 print(hash['key'], "\n"); // ハッシュの要素を出力
出力用スクリプト:
### for eRuby <% list[n] = 10 %> <%= list[i] %> <% hash["key"] = "foo" %> <%= hash["key"] %> ### for PHP <?php $list[$n] = 10; ?> <?php echo $list[$i]; ?> <?php $hash["key"] = "foo"; ?> <?php echo $hash["key"]; ?>
ハッシュは、「hash[:key]
」という形でも参照できます。
このとき、「key
」は英数字と「_
」のみからなる文字列である必要があります。
「hash[:key]
」は、各プログラム言語に応じて次のように変換されます。
ターゲット言語 | 変換結果 |
---|---|
eRuby | hash[:key] |
PHP | $hash['key'] |
JSTL | hash['key'] |
Velocity | hash.key |
PLプログラム:
print(hash[:key]);
出力用スクリプト:
### for eRuby <%= hash[:key] %> ### for PHP <?php echo $hash['key']; ?> ### for JSTL <c:out value="${hash['key']}" escapeXml="false"/> ### for Velocity $!{hash.key}
- (*3)
- 配列とハッシュとで同じ演算子を用いているため、Perlのように異なる演算子を必要とするプログラミング言語への変換は困難です。
プロパティとメソッド
オブジェクトのプロパティは、「object.property
」の形式で参照します。
また「object.method(arg1, arg2, ..)
」のように引数をつけてメソッドを呼ぶこともできます。
ただし、メソッド呼び出しはJSTLではサポートしてませんので、JSTLへの変換時にはエラーになります。
PLプログラム:
// property user.name = 'Foo'; print(user.name, "\n");
出力用スクリプト:
### for eRuby <% user.name = "Foo" %> <%= user.name %> ### for PHP <?php $user->name = "Foo"; ?> <?php echo $user->name; ?> ### for JSTL <c:set var="user" property="name" value="Foo"/> <c:out value="${user.name}" escapeXml="false"/> ### for Velocity #set($user.name = "Foo") $!{user.name}
PLプログラム:
// method call print(user.method(10, 20));
出力用スクリプト:
### for eRuby <%= user.method(10, 20) %> ### for PHP <?php echo $user->method(10, 20); ?> ### for Velocity $!{user.method(10, 20)}
またPLではオブジェクトやプロパティを参照することはできても、オブジェクトを自分で生成したりクラスを定義したりすることはできません。 それらはPLの外部で(つまりメインプログラムの中で)行われることになります。
繰り返し
繰り返しは「foreach(loopvar in list) { ... }
」で表します。
いわゆるforeach文であり、list
の要素をひとつひとつloopvar
に代入しながら繰り返しを行います。
PLプログラム:
foreach(item in list) { // listの要素をitemに代入しながら print(item, "\n"); // 繰り返し出力する }
出力用スクリプト:
### for eRuby <% for item in list do %> <%= item %> <% end %> ### for PHP <?php foreach ($list as $item) { ?> <?php echo $item; ?> <?php } ?> ### for JSTL <c:forEach var="item" items="${list}"> <c:out value="${item}" escapeXml="false"/> </c:forEach> ### for Velocity #foreach($item in $list) $!{item} #end
またwhile文も使用できます。 ただし、JSTLおよびVelocityにはwhile文に相当するカスタムタグやディレクティブがないため、 JSTLまたはVelocityへ変換しようとするとエラーになります。
PLプログラム:
i = 0; while(i < length) { i += 1; print(list[i]); }
出力用スクリプト:
### for eRuby <% i = 0 %> <% while i < length do %> <% i += 1 %> <%= list[i] %><% end %> ### for PHP <?php $i = 0; ?> <?php while ($i < $length) { ?> <?php $i += 1; ?> <?php echo $list[$i]; ?><?php } ?>
なおJavaやCのようなfor文は用意されていません。ご注意ください。
条件分岐
条件分岐は「if(condition) { ... } else if(condition) { ... } else { ... }
」で表します。
PLプログラム:
if (val > 0) { print ("* value is positive.\n"); } else if (val < 0) { print ("* value is negative.\n"); } else { print ("* value is zero.\n"); }
出力用スクリプト:
### for eRuby <% if val > 0 then %> * value is positive. <% elsif val < 0 then %> * value is negative. <% else %> * value is zero. <% end %> ### for PHP <?php if ($val > 0) { ?> * value is positive. <?php } elseif ($val < 0) { ?> * value is negative. <?php } else { ?> * value is zero. <?php } ?> ### for JSTL <c:choose><c:when test="${val gt 0}"> * value is positive. </c:when><c:when test="${val lt 0}"> * value is negative. </c:when><c:otherwise> * value is zero. </c:otherwise></c:choose> ### for Velocity #if($val > 0) * value is positive. #elseif($val < 0) * value is negative. #else * value is zero. #end
関数
PLでは、以下の関数を使用することができます。
- E(expr)
- 式 expr をサニタイズします。サニタイズはコマンドラインオプションの指定に関わらず行われます。 E()は擬似関数であり、実際にはprint文の引数でしか使用できません。
- X(expr)
- 式 expr をサニタイズしません。つまりコマンドラインオプションでサニタイズするよう指定されていても、 X(expr)で指定された式はサニタイズされません。 X()は擬似関数であり、実際にはprint文の引数でしか使用できません。
- C(expression)
-
「
expression ? ' checked="checked"' : ''
」と同じです。
- S(expression)
-
「
expression ? ' selected="selected"' : ''
」と同じです。
- D(expression)
-
「
expression ? ' disabled="disabled"' : ''
」と同じです。
- list_new()
- 新しいリストを作成します。
- list_length(list)
- リストlistの長さを返します。
- list_empty(list)
- リストlistが空ならtrueを、空でないならfalseを返します。
- hash_new()
- 新しいハッシュを作成します。
- hash_length(hash)
- ハッシュhashの長さ(要素の数)を返します。
- hash_empty(hash)
- ハッシュhashが空ならtrueを、空でないならfalseを返します。
- hash_keys(hash)
- ハッシュの全キーをリストで返します。
- str_length(string)
- 文字列stringの長さを返します。
- str_empty(string)
- 文字列stringが空ならtrueを、空でないならfalseを返します。
- str_tolower(string)
- 文字列stringを小文字にして返します。
- str_toupper(string)
- 文字列stringを大文字にして返します。
- str_trim(string)
- 文字列stringの前後から空白を取り除いた文字列を返します。
- str_index(string, char)
- 文字列stringにおいて文字charのある場所を返します。
- str_replace(string, before, after)
- 文字列stringにおいて、文字列beforeを文字列afterに置き換えたものを返します。
- str_linebreak(string)
-
文字列stringにおいて、改行のまえに
<br />
を挿入したものを返します。
- escape_xml(html_string)
- 文字列html_stringをサニタイズします。
- escape_url(url_string)
- 文字列url_stringをURL形式でエンコードします。
- escape_sql(sql_string)
-
文字列sql_string中の「
'
」「"
」「\
」をバックスラッシュでエスケープします。
どのように変換されるかは次をご覧ください。
関数名 | eRuby, ERB | PHP | JSTL1.1 | Velocity |
---|---|---|---|---|
list_new() |
[] |
array() |
- | - |
list_length(list) |
list.length |
array_length(list) |
fn:length(list) |
(list).size() |
list_empty(list) |
list.empty? |
array_length(list)==0 |
fn:length(list)==0 |
(list).size()==0 |
hash_new() |
{} |
array() |
- | - |
hash_length(hash) |
hash.length |
array_length(hash) |
fn:length(hash) |
hash.size() |
hash_empty(hash) |
hash.empty? |
array_length(hash)==0 |
fn:length(hash)==0 |
hash.size()==0 |
hash_keys(hash) |
hash.keys |
array_keys(hash) |
- | hash.keySet().toArray() |
str_length(str) |
str.lenth |
strlen(str) |
fn:length(str) |
str.length() |
str_tolower(str) |
str.downcase |
strtolower(str) |
fn:toLowerCase(str) |
str.toLowerCase() |
str_toupper(str) |
str.upcase |
strtoupper(str) |
fn:toUpperCase(str) |
str.toUpperCase() |
str_index(str,ch) |
str.index(ch) |
strchr(str,ch) |
fn:indexOf(str,ch) |
str.indexOf(ch) |
str_replace(str,before, after) |
str.gsub(before,after) |
str_replace(before,after,str) |
fn:replace(str,before,after) |
str.indexOf(ch) |
str_linebreak(str) |
str.gsub(/\r?\n/,'<br />\&') |
nl2br(str) |
fn:replace(str,'\n','<br />\n') |
str.replaceAll('$','<br />') |
escape_xml(str) |
CGI::escapeHTML(str) (when eRuby) html_escape(str) (when ERB) |
htmlspecialchars(str) |
fn:escapeXml(str) |
$esc.xml(str) |
escape_url(str) |
CGI::escape(str) (when eRuby) url_encode(str) (when ERB) |
urlencode(str) |
- | $link.setURI(str).toString() |
escape_sql(str) |
str.gsub(/['"\\\0]/,'\\\&') |
addslashes(str) |
- | $esc.sql(str) |
これら以外の関数が指定されたときは、次のように動作します。
- eRubyまたはPHPに変換するときはそのまま出力されます。
- JSTLとVelocityに変換するときは、エラーとなります。
E()とX()は、print文の引数として使われることを想定しています。 それ以外の場所では使わないでください。
Velocityでは、以下の関数を使うためにVelocityToolsをインストールする必要があります。
escape_xml()
とescape_sql()
ではEscapeToolsを使用します。escape_url()
ではLinkToolsを使用します。
詳細はそれぞれのドキュメントを参照してください。
empty
値がnullまたは空文字列かどうかを調べるための予約語「empty
」を用意しています。
「empty
」は「==
」または「!=
」の右辺にのみ置くことができ、左辺がnullか空文字列なら真を、それ以外なら偽を返します。
PLプログラム:
if (str1 == empty) { print("str1 is empty.\n"); } else if (str2 != empty) { print("str2 is not empty.\n"); }
出力用スクリプト:
### for eRuby <% if !str1 || str1.empty? then %> str1 is empty. <% elsif str2 && !str2.empty? then %> str2 is not empty. <% end %> ### for PHP <?php if (!$str1) { ?> str1 is empty. <?php } elseif ($str2) { ?> str2 is not empty. <?php } ?> ### for JSTL <c:choose><c:when test="${empty str1}"> str1 is empty. </c:when><c:when test="${not empty str2}"> str2 is not empty. </c:when></c:choose> ### for Velocity #if(! $str1 || $str1 == "") str1 is empty. #elseif($str2 && $str2 != "") str2 is not empty. #end
エレメント宣言
エレメント宣言とは、「id="name"
」または「id="mark:name"
」でマーキングされたエレメントに対して、属性を操作したり、プレゼンテーションロジックを変更するための記述です。
Kwartzでは、プレゼンテーションロジックファイルはエレメント宣言の集合として記述されます。
エレメント宣言は、「#name
」および複数の宣言部から構成されます。
-
value: expression;
-
エレメントの内容を式
expression
の値で置き換えます。
-
attrs: "attr1" expr1 , "attr2" expr2 , ... ;
-
属性
attr
の値を式expr
で置き換えます。
-
remove: "attr1" , "attr2" , ... ;
-
属性
attr
を削除します。
-
append: expr1 , expr2 , ... ;
-
タグに式
expr
の値を追加します。 <input>タグや<option>タグにおいて「checked
」や「selected
」を追加するときに使用します。
-
tagname: expression;
-
タグの名前を式
expression
で置き換えます。 StrutsやJSFのカスタムタグを利用するときに使用します。
-
plogic: { ... }
-
プレゼンテーションロジックを記述します。
{ ... }
の中では@stag
、@cont
、@etag
が使用でき、それぞれ開始タグ、内容、終了タグを表します。 また@element(other)
も使用でき、これはほかの名前がつけられたエレメントを展開することを表します。
プレゼンテーションデータ:
<ul> <li id="foo" class="foo">dummy</li> </ul> <form action="foo.cgi"> <input type="checkbox" name="user" value="Y" checked="checked" id="mark:chkbox"/> </form>
プレゼンテーションロジック:
#foo { value: item; attrs: "class" klass; plogic: { foreach (item in list) { @stag; @cont; @etag; } } } #chkbox { remove: "checked"; append: flag ? " checked" : ""; tagname: "html:text"; }
出力用スクリプト:
### for eRuby <ul> <% for item in list do %> <li id="foo" class="<%= klass %>"><%= item %></li> <% end %> </ul> <form action="foo.cgi"> <html:text type="checkbox" name="user" value="Y"<%= flag ? " checked" : "" %> /> </form> ### for PHP <ul> <?php foreach ($list as $item) { ?> <li id="foo" class="<?php echo $klass; ?>"><?php echo $item; ?></li> <?php } ?> </ul> <form action="foo.cgi"> <html:text type="checkbox" name="user" value="Y"<?php echo $flag ? " checked" : ""; ?> /> </form> ### for JSTL 1.1 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> <ul> <c:forEach var="item" items="${list}"> <li id="foo" class="<c:out value="${klass}" escapeXml="false"/>"><c:out value="${item}" escapeXml="false"/></li> </c:forEach> </ul> <form action="foo.cgi"> <html:text type="checkbox" name="user" value="Y"<c:out value="${flag ? ' checked' : ''}" escapeXml="false"/> /> </form> ### for Velocity <ul> #foreach($item in $list) <li id="foo" class="$!{klass}">$!{item}</li> #end </ul> <form action="foo.cgi"> #if($flag) <html:text type="checkbox" name="user" value="Y" checked /> #else <html:text type="checkbox" name="user" value="Y" /> #end </form>
ドキュメント宣言
#DOCUMENT { ... }
は、ドキュメントのための特殊なエレメント宣言です。
この宣言はドキュメント全体の情報を表し、次の宣言部を使用します。
-
begin: { ... }
- 出力用スクリプトの先頭に、指定されたPLコードを追加します。
-
end: { ... }
- 出力用スクリプトの末尾に、指定されたPLコードを追加します。
-
require: "filename1" , "filename2", ... ;
- プレゼンテーションロジックファイルを読み込みます。
-
global: varname1 , varname2 , ... ;
- グローバル変数を列挙します。現在は何も使われていませんが、将来は使う予定です。
-
local: varname1 , varname2 , ... ;
- ローカル変数を列挙します。現在は何も使われていませんが、将来は使う予定です。
プレゼンテーションデータ:
<ul id="mark:list"> <li id="value:item">foo</li> </ul>
PLプログラム:
#DOCUMENT { begin: { list = context[:list]; } end: { print("<!-- copyright(c) 2005 kuwata-lab.com ALL RIGHTS RESERVERD. -->\n"); } global: context; } #list { plogic: { @stag; foreach (item in list) @cont; @etag; } }
出力用スクリプト:
### for eRuby <% list = context[:list] %> <ul> <% for item in list do %> <li><%= item %></li> <% end %> </ul> <!-- copyright(c) 2005 kuwata-lab.com ALL RIGHTS RESERVERD. --> ### for PHP <?php $list = $context['list']; ?> <ul> <?php foreach ($list as $item) { ?> <li><?php echo $item; ?></li> <?php } ?> </ul> <!-- copyright(c) 2005 kuwata-lab.com ALL RIGHTS RESERVERD. --> ### for JSTL <c:set var="list" value="${context['list']}"/> <ul> <c:forEach var="item" items="${list}"> <li><c:out value="${item}" escapeXml="false"/></li> </c:forEach> </ul> <!-- copyright(c) 2005 kuwata-lab.com ALL RIGHTS RESERVERD. --> ### for Velocity #set($list = $context.list) <ul> #foreach($item in $list) <li>$!{item}</li> #end </ul> <!-- copyright(c) 2005 kuwata-lab.com ALL RIGHTS RESERVERD. -->
ターゲット言語のプログラムコード
ターゲット言語(Ruby,PHP,Javaなど)のプログラムコードを直接記述することもできます。 Kwartzではターゲット言語で書かれたコードをRawcodeと呼んでいます。
- 「
<%=expression%>
」または「<?=expression?>
」は、ターゲット言語で書かれた式です。 これはRawcode式(Rawcode Expression)といい、文法的には文字列や数字と同じようにリテラルとして扱われます。 - 「
<%statement%>
」または「<?statement?>
」は、ターゲット言語で書かれた文です。 これはRawcode文(Rawcode Statement)といい、ひとつの文として扱われます。 ただし行末の「;
」は必要ありません。
次の例は、Rubyコードを直接記述した例です。
PLプログラム:
// Rawcode式 hash = <%= { :a => 123, :b => 456, :c => 789, } %>; // Rawcode文 <% hash.each do |key, value| %> print("key=", key, " value=", value, "\n"); <% end %>
出力用スクリプト:
### for eRuby <% hash = { :a => 123, :b => 456, :c => 789, } %> <% hash.each do |key, value| %> key=<%= key %> value=<%= value %> <% end %>
次の例は、PHPのコードを直接記述した例です。
PLプログラム:
// Rawcode式 hash = <?= array("a"=>123, "b"=>456, "c"=>789) ?>; // Rawcode文 <?php foreach($hash as $key => $value) { ?> print("key=", key, " value=", value, "\n"); <?php } ?>
出力用スクリプト:
### for PHP <?php $hash = array("a"=>123, "b"=>456, "c"=>789); ?> <?php foreach($hash as $key => $value) { ?> key=<?php echo $key; ?> value=<?php echo $value; ?> <?php } ?>
Rawcode文は、エレメント宣言の「plogic:」部に記述できます。
またRawcode式は、「value:」部や「attrs:」部に記述できます。
なおRawcode式を「X(<%= ... %>)
」のように記述すれば、サニタイズしません。
Rawcodeを用いてKwartzをRuby on Railsで使うサンプルが、Kwartzアーカイブのexamples/rails1ディレクトリにあります。 参考にしてください。
ターゲット言語のプログラムコードを直接記述した場合は、当然ですが他の言語では使用できなくなります。 それでも構わない場合にのみ使用してください。
グローバル変数とローカル変数
Kwartzでは、メインプログラムから出力用プログラムに渡される変数をテンプレートグローバル変数、テンプレートの中だけで使用される変数をテンプレートローカル変数と呼んでいます。
例えば次のようなプレゼンテーションデータとプレゼンテーションロジックを考えます。
プレゼンテーションデータ(analyze.html):
<table> <caption id="value:title">Sample</caption> <tr id="mark:items" bgcolor="@{color}@"> <td id="value:item">Foo</td> </tr> </table>
プレゼンテーションロジック(analyze.plogic):
#items { plogic: { ctr = 0; foreach (item in list) { ctr += 1; color = ctr%2 == 0 ? '#FFCCCC' : '#CCCCFF'; @stag; @cont; @etag; } } }
いくつかの変数がでてきますが、これらは次のように分類できます。
- テンプレートグローバル変数
-
変数「
title
」と「list
」は、メインプログラムからテンプレートに渡される変数であり、メインプログラムで値を設定する必要があります。 Kwartzではこれをテンプレートグローバル変数と呼んでいます。 - テンプレートローカル変数
-
変数「
item
」と「ctr
」と「color
」はテンプレートの中だけで使用される変数であり、メインプログラムで設定する必要はありません。 Kwartzではこれをテンプレートローカル変数と呼んでいます。
kwartzコマンドにオプション「-a analyze
」をつけて起動すると、テンプレートを分析してテンプレートグローバル変数とテンプレートローカル変数を報告してくれます。
$ kwartz -p analyze.plogic -a analyze analyze.html Global: title list Local: ctr item color
このとき、Kwartzは次のようなルールでグローバルかローカルかを判定しています。
- 変数が初めて現れたときに…
- 代入文の左辺に現れた変数はテンプレートローカル変数
- foreach文のループ変数として現れた変数はテンプレートローカル変数
- それ以外はテンプレートグローバル変数
またテンプレートグローバル変数へ代入したり、テンプレートグローバル変数をループ変数としていると、分析時に警告を出します。 なぜなら、テンプレートシステムはメインプログラムで設定されたデータの表示のみを行うべきであり、それらを変更すべきではないから、つまりテンプレートグローバル変数を変更すべきではないからです(変更してよいのはテンプレートローカル変数のみのはずです)。
テンプレート(プレゼンテーションデータとプレゼンテーションロジック)が複雑になると、メインプログラムで設定しなければならない変数がどれか、わかりづらくなることがあります。 そのようなときは、この分析機能を利用してください。変数名のタイプミスも見つけやすくなります。
未実装(または検討中)の機能
以下の機能は実装されていませんが、将来において実装されるかもしれません。
- break, continue
- ユーザ定義関数
- JSTLにおける配列やハッシュの作成
ディレクティブ
ディレクティブとは?
Kwartzでは、プレゼンテーションデータの中にプレゼンテーションロジックを埋め込むこともできます。 そのための命令を「ディレクティブ(Directive)」といいます。
ディレクティブとは、プレゼンテーションデータの中にプレゼンテーションロジックを埋め込むための命令です。
Kwartzでは、ディレクティブはid属性またはid属性を使用します(使い方はどちらも同じです)。
「id="name"
」や「id="mark:name"
」も、「マーキング」というディレクティブです。
Kwartzではせっかくプレゼンテーションデータとプレゼンテーションロジックとを分離することができるのに、なぜ両者を一体化するような機能も用意されているのでしょう?
それは、開発者の好みに応じてどちらも選べるようにするため、つまり「選択可能性(choosability)」を高めるためです。 Kwartzは、開発者にどちらか一方を押しつけるようなことはしません。 分離するほうが望ましいのであれば分離すればよいし、一体化するほうが好みであれば一体化すればよいのです。
また両者を一体化すると、他のテンプレートと差別化できないと思われるかもしれません。 しかし一体化してもなお、Kwartzは他のテンプレートと比べて次のような利点があります。
- HTMLデザインを崩しません(Jakarta VelocityやTemplate-Toolkitと比べてみてください)。
- 複雑なプログラミングが必要ありません(DOMプログラミングが必要なEnhydra XMLCと比べてみてください)。
- 実行時の動作が軽くて高速です(amritaと比べてみてください)。
- XMLやHTMLだけでなく、どのようなテキスト形式でも利用できます(Enhydra XMLCやamritaと比べて見てください)。
- 各種のプログラミング言語で使用できます(このようなテンプレートシステムは他にありません!)。
マーキング
「id="name"
」または「id="mark:name"
」とすることで、マーキングを行います。
マーキングとは、エレメントに対してその名前で目印をつけることです。
「id="name"
」と「id="mark:name"
」との違いは、コンパイルされると前者ではid属性が残るのに対し後者は取り除かれるという点です。
またkw:d属性は必ず取り除かれます。
プレゼンテーションデータ:
<div id="foo">foo</div> <div id="mark:bar">bar</div>
出力用スクリプト:
### for eRuby <div id="foo">foo</div> <div>bar</div> ### for PHP <div id="foo">foo</div> <div>bar</div> ### for JSTL <div id="foo">foo</div> <div>bar</div> ### for Velocity <div id="foo">foo</div> <div>bar</div>
値の出力
「@{expression}@
」は、式の値を出力するディレクティブです。
このパターンは、設定ファイルのEMBED_PATTERNに設定されています。
プレゼンテーションデータ:
Hello @{user.name}@!
出力用プログラム:
### for eRuby Hello <%= user.name %>! ### for PHP Hello <?php echo $user->name; ?>! ### for JSTL Hello <c:out value="${user.name}" escapeXml="false"/>! ### for Velocity Hello $!{user.name}!
コンパイル時に、コマンドオプション-e
を指定した場合は、式をサニタイズして出力します。
このとき、文字列や数値はサニタイズされず、式のみがサニタイズされることに注意してください。
出力用プログラム(コマンドオプション-e
をつけた場合):
### for eRuby Hello <%= CGI::escapeHTML((user.name).to_s) %>! ### for PHP Hello <?php echo htmlspecialchars($user->name); ?>! ### for JSTL Hello <c:out value="${user.name}"/>! ### for Velocity Hello $!esc.html($user.name)!
コマンドオプションの有無に関わらずサニタイズをする/しないを指定するには、関数E()
とX()
を使用します。
E(expr)
は式expr
をサニタイズし、X(expr)
はサニタイズしません。
プレゼンテーションデータ:
With sanitizing: @{E(var)}@! Without sanitizing: @{X(var)}@!
出力用プログラム:
### for eRuby With sanitizing: <%= CGI::escapeHTML((var).to_s) %>! Without sanitizing: <%= var %>! ### for PHP With sanitizing: <?php echo htmlspecialchars($var); ?>! Without sanitizing: <?php echo $var; ?>! ### for JSTL With sanitizing: <c:out value="${var}"/>! Without sanitizing: <c:out value="${var}" escapeXml="false"/>! ### for Velocity With sanitizing: $!esc.html($var)! Without sanitizing: $!{var}!
. .
値の出力2
「id="value:expression"
」とすることで、内容のかわりに式の値を出力します。
ダミーデータを利用できるため、「@{expression}@
」と比べてHTMLデザインがより崩れません。
プレゼンテーションデータ:
<li id="value:hash['name']">foo</li>
出力用プログラム:
### for eRuby <li><%= hash["name"] %></li> ### for PHP <li><?php echo $hash["name"]; ?></li> ### for JSTL <li><c:out value="${hash['name']}" escapeXml="false"/></li> ### for Velocity <li>$!{hash["name"]}</li>
また「id="Value:expr"
」でサニタイズすることを、「id="VALUE:expr"
」でサニタイズしないことを指定できます。
これらはそれぞれ「id="value:E(expr)"
」や「id="value:X(expr)"
」と同じです。
属性値の設定
「id="attr:name=value"
」または「id="attr:name:value"
」とすることで、タグの属性値を設定できます。
これを用いると、「@{...}@
」を使わずに属性値を設定でき、またダミーの属性値を設定できます。
次の例では、属性classにダミーの属性値 "odd
" を設定していますが、実際には変数klass
の値を用いるようにしています。
プレゼンテーションデータ:
<tr class="odd" id="attr:class=klass"> <td>foo</td> </tr>
出力用プログラム:
### for eRuby <tr class="<%= klass %>"> <td>foo</td> </tr> ### for PHP <tr class="<?php echo $klass; ?>"> <td>foo</td> </tr> ### for JSTL <tr class="<c:out value="${klass}" escapeXml="false"/>"> <td>foo</td> </tr> ### for Velocity <tr class="$!{klass}"> <td>foo</td> </tr>
また「id="Attr:name=value"
」でサニタイズすることを、「id="ATTR:name=value"
」でサニタイズしないことを指定できます。
これらはそれぞれ「id="attr:name=E(value)"
」や「id="attr:name=X(value)"
」と同じです。
なお「;
」で区切ることにより、「attr:name=value
」を複数設定したり他のテンプレートコマンドと一緒に設定したりできます。
プレゼンテーションデータ:
<font id="if:message!=empty;attr:class=klass;attr:bgcolor=color"> @{message}@ </font>
出力用スクリプト:
### for eRuby <% if message && !message.empty? then %> <font class="<%= klass %>" bgcolor="<%= color %>"> <%= message %> </font> <% end %> ### for PHP <?php if ($message) { ?> <font class="<?php echo $klass; ?>" bgcolor="<?php echo $color; ?>"> <?php echo $message; ?> </font> <?php } ?> ### for JSTL <c:if test="${not empty message}"> <font class="<c:out value="${klass}" escapeXml="false"/>" bgcolor="<c:out value="${color}" escapeXml="false"/>"> <c:out value="${message}" escapeXml="false"/> </font> </c:if> ### for Velocity #if($message && $message != "") <font class="$!{klass}" bgcolor="$!{color}"> $!{message} </font> #end
属性の追加
「id="append:expression"
」とすることで、タグの中に式の値を追加できます。
これは主に「<input ... checked />」や「<option ... selected></option>」を実現するための機能です。
プレゼンテーションデータ:
<option name="lang" value="ruby" id="append:lang=='ruby'?' selected':''">Ruby</option> <input type="radio" name="gender" value="M" id="append:gender=='M'?' checked':''">
出力用スクリプト:
### for eRuby <option name="lang" value="ruby"<%= lang == "ruby" ? " selected" : "" %>>Ruby</option> <input type="radio" name="gender" value="M"<%= gender == "M" ? " checked" : "" %>> ### for PHP <option name="lang" value="ruby"<?php echo $lang == "ruby" ? " selected" : ""; ?>>Ruby</option> <input type="radio" name="gender" value="M"<?php echo $gender == "M" ? " checked" : ""; ?>> ### for JSTL 1.1 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> <option name="lang" value="ruby"<c:out value="${lang eq 'ruby' ? ' selected' : ''}" escapeXml="false"/>>Ruby</option> <input type="radio" name="gender" value="M"<c:out value="${gender eq 'M' ? ' checked' : ''}" escapeXml="false"/>> ### for JSTL 1.0 <%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %> <c:choose><c:when test="${lang eq 'ruby'}"> <option name="lang" value="ruby" selected></c:when><c:otherwise> <option name="lang" value="ruby"></c:otherwise></c:choose> Ruby</option> <c:choose><c:when test="${gender eq 'M'}"> <input type="radio" name="gender" value="M" checked> </c:when><c:otherwise> <input type="radio" name="gender" value="M"> </c:otherwise></c:choose>
なお「checked="checked"
」「selected="selected"
」「disabled="disabled"
」の出力を簡単にするための機能として、関数「C(expr)
」「S(expr)
」「D(expr)
」が用意されています。
これらは、式expr
が真のときにそれぞれ「checked="checked"
」「selected="selected"
」「disabled="disabled"
」を出力します。
プレゼンテーションデータ:
<option name="lang" value="ruby" id="append:S(lang=='ruby')">Ruby</option> <input type="radio" name="gender" value="M" id="append:C(gender=='M')" />Male <input type="radio" name="os" value="win" id="append:D(os=='mac')" />Windows
出力用スクリプト:
### for PHP <option name="lang" value="ruby"<?php echo $lang == "ruby" ? " selected=\"selected\"" : ""; ?>>Ruby</option> <input type="radio" name="gender" value="M"<?php echo $gender == "M" ? " checked=\"checked\"" : ""; ?> />Male <input type="radio" name="os" value="win"<?php echo $os == "mac" ? " disabled=\"disabled\"" : ""; ?> />Windows ### for eRuby <option name="lang" value="ruby"<%= lang == "ruby" ? " selected=\"selected\"" : "" %>>Ruby</option> <input type="radio" name="gender" value="M"<%= gender == "M" ? " checked=\"checked\"" : "" %> />Male <input type="radio" name="os" value="win"<%= os == "mac" ? " disabled=\"disabled\"" : "" %> />Windows ### for JSTL 1.1 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> <option name="lang" value="ruby"<c:out value="${lang eq 'ruby' ? ' selected="selected"' : ''}" escapeXml="false"/>>Ruby</option> <input type="radio" name="gender" value="M"<c:out value="${gender eq 'M' ? ' checked="checked"' : ''}" escapeXml="false"/> />Male <input type="radio" name="os" value="win"<c:out value="${os eq 'mac' ? ' disabled="disabled"' : ''}" escapeXml="false"/> />Windows ### for JSTL 1.0 <%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %> <c:choose><c:when test="${lang eq 'ruby'}"> <option name="lang" value="ruby" selected="selected"></c:when><c:otherwise> <option name="lang" value="ruby"></c:otherwise></c:choose> Ruby</option> <c:choose><c:when test="${gender eq 'M'}"> <input type="radio" name="gender" value="M" checked="checked" /></c:when><c:otherwise> <input type="radio" name="gender" value="M" /></c:otherwise></c:choose> Male <c:choose><c:when test="${os eq 'mac'}"> <input type="radio" name="os" value="win" disabled="disabled" /></c:when><c:otherwise> <input type="radio" name="os" value="win" /></c:otherwise></c:choose> Windows
変数への代入
「id="set:var=value"
」は、変数varに値valueを設定します。
「=
」だけでなく「+=
」「-=
」「*=
」「/=
」「.=
」が使用できます。
プレゼンテーションデータ:
<dt id="set:var=value">foo</dt> <dd id="set:count+=1">123</dd>
出力用プログラム:
### for eRuby <% var = value %> <dt>foo</dt> <% count += 1 %> <dd>123</dd> ### for PHP <?php $var = $value; ?> <dt>foo</dt> <?php $count += 1; ?> <dd>123</dd> ### for JSTL <c:set var="var" value="${value}"/> <dt>foo</dt> <c:set var="count" value="${count + 1}"/> <dd>123</dd> ### for Velocity #set($var = $value) <dt>foo</dt> #set($count = $count + 1) <dd>123</dd>
条件分岐
「id="if:expression"
」とすることで、条件分岐を行います。
elseやelseifも使用できます。
プレゼンテーションデータ:
<div id="if:value > 0"> Value is positive. </div> <div id="elseif:value < 0"> Value is negative. </div> <div id="else:"> Value is zero. </div>
出力用プログラム:
### for eRuby <% if value > 0 then %> <div> Value is positive. </div> <% elsif value < 0 then %> <div> Value is negative. </div> <% else %> <div> Value is zero. </div> <% end %> ### for PHP <?php if ($value > 0) { ?> <div> Value is positive. </div> <?php } elseif ($value < 0) { ?> <div> Value is negative. </div> <?php } else { ?> <div> Value is zero. </div> <?php } ?> ### for JSTL <c:choose><c:when test="${value gt 0}"> <div> Value is positive. </div> </c:when><c:when test="${value lt 0}"> <div> Value is negative. </div> </c:when><c:otherwise> <div> Value is zero. </div> </c:otherwise></c:choose> ### for Velocity #if($value > 0) <div> Value is positive. </div> #elseif($value < 0) <div> Value is negative. </div> #else <div> Value is zero. </div> #end
「elseif
」や「else
」を使う場合は、直前に空行を入れないようにしてください。
繰り返し(foreach)
「id="foreach:loopvar=list"
」(または「id="foreach:loopvar:list"
」)とすることで、リストlist
の要素をひとつずつ変数loopvar
に代入しながら、繰り返しを行います。
プレゼンテーションデータ:
<tr id="foreach:item=list"> <td>@{item}@</td> </tr>
出力用プログラム:
### for eRuby <% for item in list do %> <tr> <td><%= item %></td> </tr> <% end %> ### for PHP <?php foreach ($list as $item) { ?> <tr> <td><?php echo $item; ?></td> </tr> <?php } ?> ### for JSTL <c:forEach var="item" items="${list}"> <tr> <td><c:out value="${item}" escapeXml="false"/></td> </tr> </c:forEach> ### for Velocity #foreach($item in $list) <tr> <td>$!{item}</td> </tr> #end
繰り返し(loop)
「id="loop:loopvar=list"
」(または「id="loop:loopvar:list"
」)とすることで、リストlist
の要素をひとつずつ変数loopvar
に代入しながら繰り返しを行います。
「id="foreach:loopvar=list)"
」とよく似ていますが、開始タグと終了タグを含めず、内容だけ繰り返す点が異なります。
<dl></dl>で使うと非常に便利です。
プレゼンテーションデータ:
<dl id="loop:item=list"> <dt>@{item.text}@</dt> <dd>@{item.desc}@</dd> </dl>
出力用プログラム:
### for eRuby <dl> <% for item in list do %> <dt><%= item.text %></dt> <dd><%= item.desc %></dd> <% end %> </dl> ### for PHP <dl> <?php foreach ($list as $item) { ?> <dt><?php echo $item->text; ?></dt> <dd><?php echo $item->desc; ?></dd> <?php } ?> </dl> ### for JSTL <dl> <c:forEach var="item" items="${list}"> <dt><c:out value="${item.text}" escapeXml="false"/></dt> <dd><c:out value="${item.desc}" escapeXml="false"/></dd> </c:forEach> </dl> ### for Velocity <dl> #foreach($item in $list) <dt>$!{item.text}</dt> <dd>$!{item.desc}</dd> #end </dl>
カウンタつき繰り返し(Foreach,Loop)
「id="Foreach:var=list)"
」や「id="Loop:var=list)"
」を使うと、カウンタを増やしながら繰り返しを行います。
カウンタは1から始まり、変数名はvar_ctr
です。
プレゼンテーションデータ:
<tr id="Foreach:item=list"> <td>@{item_ctr}@</td> <td>@{item}@<td> </tr>
出力用プログラム:
### for eRuby <% item_ctr = 0 %> <% for item in list do %> <% item_ctr += 1 %> <tr> <td><%= item_ctr %></td> <td><%= item %><td> </tr> <% end %> ### for PHP <?php $item_ctr = 0; ?> <?php foreach ($list as $item) { ?> <?php $item_ctr += 1; ?> <tr> <td><?php echo $item_ctr; ?></td> <td><?php echo $item; ?><td> </tr> <?php } ?> ### for JSTL <c:set var="item_ctr" value="0"/> <c:forEach var="item" items="${list}"> <c:set var="item_ctr" value="${item_ctr + 1}"/> <tr> <td><c:out value="${item_ctr}" escapeXml="false"/></td> <td><c:out value="${item}" escapeXml="false"/><td> </tr> </c:forEach> ### for Velocity #set($item_ctr = 0) #foreach($item in $list) #set($item_ctr = $item_ctr + 1) <tr> <td>$!{item_ctr}</td> <td>$!{item}<td> </tr> #end
トグルつき繰り返し(FOREACH,LOOP)
「id="FOREACH:var=list"
」や「id="LOOP:var=list"
」とすると、トグルつきの繰り返しを行うことができます。
トグルは、繰り返し回数が奇数回か偶数回かによって、値が入れ替わります。
トグル変数の名前はvar_tgl
です。
トグルの値はデフォルトで「"odd"
」と「"even"
」が使われますが、コマンドオプション --odd と --even で指定できます。
また設定ファイルkwartz/config.rbの定数ODDとEVENでも指定できます。
プレゼンテーションデータ:
<table> <tbody id="LOOP:item=list"> <tr class="@{item_tgl}@"> <td>@{item}@</td> </tr> </tbody> </table>
出力用プログラム:
### for eRuby <table> <tbody> <% item_ctr = 0 %> <% for item in list do %> <% item_ctr += 1 %> <% item_tgl = item_ctr % 2 == 0 ? "even" : "odd" %> <tr class="<%= item_tgl %>"> <td><%= item %></td> </tr> <% end %> </tbody> </table> ### for PHP <table> <tbody> <?php $item_ctr = 0; ?> <?php foreach ($list as $item) { ?> <?php $item_ctr += 1; ?> <?php $item_tgl = $item_ctr % 2 == 0 ? "even" : "odd"; ?> <tr class="<?php echo $item_tgl; ?>"> <td><?php echo $item; ?></td> </tr> <?php } ?> </tbody> </table> ### for JSTL <table> <tbody> <c:set var="item_ctr" value="0"/> <c:forEach var="item" items="${list}"> <c:set var="item_ctr" value="${item_ctr + 1}"/> <c:set var="item_tgl" value="${item_ctr % 2 eq 0 ? 'even' : 'odd'}"/> <tr class="<c:out value="${item_tgl}" escapeXml="false"/>"> <td><c:out value="${item}" escapeXml="false"/></td> </tr> </c:forEach> </tbody> </table> ### for Velocity <table> <tbody> #set($item_ctr = 0) #foreach($item in $list) #set($item_ctr = $item_ctr + 1) #if($item_ctr % 2 == 0) #set($item_tgl = "even") #else #set($item_tgl = "odd") #end <tr class="$!{item_tgl}"> <td>$!{item}</td> </tr> #end </tbody> </table>
繰り返し(while)
「id="while:expression"
」とすることで、繰り返しを行うことができます。
またJSPとVelocityでは、whileを変換しようとするとエラーになります。 これは、whileに対応するカスタムタグやディレクティブがないからです。
プレゼンテーションデータ:
<tr id="while:row=sth.fetch()"> <td>@{row[0]}@</td> </tr>
出力用プログラム:
### for eRuby <% while row = sth.fetch() do %> <tr> <td><%= row[0] %></td> </tr> <% end %> ### for PHP <?php while ($row = $sth->fetch()) { ?> <tr> <td><?php echo $row[0]; ?></td> </tr> <?php } ?>
ダミーデータ
「id="dummy:str"
」とすることで、そのノードをダミーデータとみなして読み飛ばします。
str
は、id属性の値が重ならないようにするためのものであり、意味はありません。
プレゼンテーションデータ:
<tr id="dummy:d1"> <td>bar</td> </tr> <tr id="dummy:d2"> <td>baz</td> </tr>
中間コード:
// 何も出力されない
出力用プログラム:
// 何も出力されない
エレメントの置換
「id="replace:name"
」とすることで、そのエレメントを別のエレメントに置き換えることができます。
プレゼンテーションデータ:
<html> <body> <!-- ナビゲーション --> <div id="mark:breadcrumbs"> <a href="/">Home</a> > <a href="/kwartz">Kwartz</a> > <a href="/kwartz/ruby">Kwartz-ruby</a> </div> .... <div id="replace:breadcrumbs"> Home > Kwartz > Kwartz-ruby </span> </div> </html
出力用スクリプト:
<html> <body> <!-- ナビゲーション --> <div> <a href="/">Home</a> > <a href="/kwartz">Kwartz</a> > <a href="/kwartz/ruby">Kwartz-ruby</a> </div> .... <div> <a href="/">Home</a> > <a href="/kwartz">Kwartz</a> > <a href="/kwartz/ruby">Kwartz-ruby</a> </div> </html
なおコマンドラインオプション「-i file1,file2,...
」を指定すると、
他のファイルのエレメントを利用できます。
プレースホルダ
「id="placeholder:name"
」とすることで、そのエレメントの内容を別のエレメントで置き換えます。
通常は、コマンドラインオプション「-i file1,file2,...
」とともに使用し、
他のファイルで定義されたエレメントを取り込むために使われます。
プレゼンテーションデータ(article.html):
<html> <body> <div id="mark:article"> <p>Kwartz is a template system, which realized the concept <strong>`Separation of Presentation Logic and Presentation Data'(SoPL/PD)</strong>. </p> </div> </body> </html>
プレゼンテーションデータ(layout.html):
<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN"> <html lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <link rel="stylesheet" type="text/css" href="design.css"> </head> <body> <table border="0"> <tr> <td width="400" id="placeholder:article"> aaa<br> bbb<br> ccc<br> ddd<br> </td> </tr> </table> </body> </html>
コンパイル:
$ kwartz -i article.html layout.html
出力用スクリプト:
<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN"> <html lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <link rel="stylesheet" type="text/css" href="design.css"> </head> <body> <table border="0"> <tr> <td width="400"> <div> <p>Kwartz is a template system, which realized the concept <strong>`Separation of Presentation Logic and Presentation Data'(SoPL/PD)</strong>. </p> </div> </td> </tr> </table> </body> </html>
プレゼンテーションデータファイルの読み込み
「id="include:filename"
」で他のプレゼンテーションデータファイル(HTMLファイル)を読み込むことができます。
読み込まれる側のファイルでも、ディレクティブを使用できます。
プレゼンテーションデータ(copyright.html):
<!-- begin footer --> <center> copyright© <span id="value:year">2005</span> kuwata-lab all rights reserverd </center> <!-- end footer -->
プレゼンテーションデータ(mainpage.html):
<html> <body> ... main contents ... <div id="include:copyright.html"> ... copyright ... </div> </body> </html>
コンパイル:
$ kwartz -l eruby mainpage.html > mainpage.view
出力用スクリプト:
### for eRuby <html> <body> ... main contents ... <!-- begin footer --> <center> copyright© <%= year %> kuwata-lab all rights reserverd </center> <!-- end footer --> </body> </html>
「include
」ディレクティブのほかに、「Include
」と「INCLUDE
」が使用できます。
- 「
include
」ディレクティブは、読み込んだファイルでそのエレメントを置き換えます。 - 「
Include
」ディレクティブは、読み込んだファイルをそのエレメントの前に追加します。 - 「
INCLUDE
」ディレクティブは、読み込んだファイルをそのエレメントの後ろに追加します。
include
ディレクティブで読み込むファイルは、別ディレクトリに置くことができます。
ファイルが置いてあるディレクトリは、コマンドラインオプション --incdirs=dir1,dir2,...
または設定ファイルの INCDIRS
で指定できます。
id属性とkw:d属性について
Kwartzでは、ディレクティブを記述するのにid属性とkw:d属性が使用できます。 ここでは、両者の使い分けについて説明します。
- id属性もkw:d属性も、機能としては同じです。
今までid属性で説明していましたが、すべてkw:d属性に書いても動作します。
- ひとつのタグにid属性とkw:d属性の両方を記述した場合、kw:d属性のほうが優先されます。
例えば「
id="name" kw:d="foreach:item=list"
」とした場合、kw:d属性のほうが有効となります。
- ただし、kw:d属性に記述したディレクティブが
attr
のみの場合は、 id属性のディレクティブも有効となります。 例えば「id="name" kw:d="attr:href=url"
」とした場合、そのエレメントは名前name
を使ってマーキングされます。
- HTMLの仕様では、id属性の値に含めることのできる記号はアンダーバー(
_
)、コロン(:
)、ピリオド(.
)、ハイフン(-
)のみです。 そのため、id="foreach:item=list"
やid="attr:name=value"
という記述はHTMLの仕様からみると正しくありませんので、id="foreach:item:list"
やid="attr:name:value"
と書くほうがよいでしょう。
- kw:d属性の名前は、コマンドラインオプション
--dattr=xxx
で変更することができます。 例えばkw:d属性のかわりにstyle属性を使う場合は、 --dattr=style としてください。 また設定ファイルのDATTR
でも変更できます。
注意事項
ディレクティブを使用する際の注意事項です。
- ひとつのid属性またはkw:d属性にはひとつのディレクティブしか記述できません。
例えば「
id="set:var=100;value:var"
」のような記述はエラーになります。## NG <span id="set:var=100;value:var">foo</span>
- ただし、attrディレクティブとappendディレクティブだけは他のディレクティブといっしょに記述できます。
また複数のattrディレクティブとappendディレクティブを設定することもできます。
## OK <foo id="foreach:item=list;attr:class=item.class;attr:href=item.url"> .... </foo>
- タグにディレクティブを含めた場合、終了タグは省略できません。
また
<foo .../>
のような空要素タグは使用できます。## NG <ul> <li id="value:item">foo </ul> ## OK <a id="attr:name=refname"/>
- ディレクティブしか含まないような<span></span>は、削除されます。
例えば「
Hello <span id="value:name">World</span>!
」というプレゼンテーションデータは、<span></span>が削除されて「Hello <%= name %>!
」(eRubyの場合)という出力ファイルになります。## プレゼンテーションデータ Hello <span id="value:name">World</span>! ## 出力用スクリプト for eRuby Hello <%= name %>!
- ディレクティブを含むタグでは、ほかの属性は必ず「
attr="value"
」の形で記述し、属性名や属性値を省略しないようにしてください。 これはHTML/XML以外でもKwartzを使用できるようにするための意図した仕様であり、バグではありません。## NG <input type="checkbox" id="foreach:item=list" checked/> ## OK <input type="checkbox" id="foreach:item=list" checked="checked"/> ## NG <option id="attr:value=val" @{flag ? 'selected' : ''}@/> ## OK <option value="@{val}@" @{flag ? 'selected' : ''}@>
プレゼンテーションロジックファイル
プレゼンテーションロジックファイルの書き方です。
プレゼンテーションロジック:
「id="mark:name"」でマーキングされたエレメントの宣言 #name { // 内容のかわりに出力する式 value: expression; // 属性(名前と値) attrs: "attr1" expr1, "attr2" expr2, "attr3" expr3; // 削除する属性の名前 remove: "attr1", "attr2", "attr3"; // 開始タグに追加する式 append: expr1, expr2, expr3; // タグ名 tagname: "tagname", // プレゼンテーションロジック本体 plogic: { @stag; @cont; @etag; } } // ドキュメント宣言 #DOCUMENT { // はじめに実行されるロジック begin: { ... } // 最後に実行されるロジック end: { ... } // 他のプレゼンテーションロジックファイルを読み込む require: "file1.plogic", "file2.plogic"; }
コマンドラインオプション
テンプレートを出力用プログラムへコンパイルするには、kwartzコマンドを使用します。
使い方:
kwartz [options...] [-p plogic ] pdata.html > output-script
オプションは次の通りです。
- -h, --help
- ヘルプを表示。
- -v
- バージョン情報を表示
- -a action
-
実行する処理。actionには次のどれかを指定する(デフォルトはcompile)。
- compile
- プレゼンテーションデータとプレゼンテーションロジックを読み込み、出力用スクリプトを生成します。
- analyze
- プレゼンテーションデータとプレゼンテーションロジックを読み込み、変数のスコープを解析します。
- defun
- プレゼンテーションデータとプレゼンテーションロジックを読み込み、RubyまたはPHPの関数に変換します。
- convert
- プレゼンテーションデータを読み込み、PLプログラムに変換します。デバッグ用です。
- transalte
- PLプログラムを読み込み、出力用スクリプトに変換します。デバッグ用です。
- -e , -s
-
サニタイズを行う。
--escape=true
と同じ。
- -i file1,file2,...
-
外部ファイルで定義されたエレメントをインポートする。
主にplaceholderディレクティブ(「
id="placeholder:name
」)のために使用される。
- -l lang
- ターゲット言語を指定。指定できるのは eruby, erb, php, jstl11, jstl10, velocity.
- -p plogic-file
-
プレゼンテーションロジックのファイル名。「
,
」で区切ることで、複数のファイル名を指定できる。
- -R arg
-
特殊オプション。今のところ以下の引数のみ指定可能。
- ails ... 「
-l erb --globalvar-prefix='@'
」と同じ。Ruby on Rails用のファイルを出力する。
- ails ... 「
- --charset=charset
-
文字コード。JSTLにおいて '
<%@ page contentType="text/html; charset=charset "%>
' を出力する。
- --dname=name
- ディレクティブで使用する属性名。デフォルトは 'kw:d'。
- --escape=true|false
- 式をサニタイズして出力する。値が省略されたときはtrueが指定されたものとみなす。
- --even=value
-
偶数のときの値。デフォルトは「
'even'
」。ディレクティブFOREACHとLISTで使われる。
- --extract=name
- 指定された名前でマーキングされたエレメントだけを抽出する。
- --footer=string
- フッター文字列。
- --header=string
-
ヘッダー文字列。
JSPではデフォルトで '
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
' が設定される。 これを出力したくないときは--header=false
とする。
- --indent=' '
- 出力用スクリプトのインデントを指定する。
- --incdirs=dir1,dir2,...
-
include
ディレクティブで読み込むファイル(プレゼンテーションデータファイル)のディレクトリを指定する。
- --odd=value
-
奇数のときの値。デフォルトは「
'odd'
」。ディレクティブFOREACHとLISTで使われる。
- --localvar-prefix=string
- テンプレートローカル変数につけるプレフィックスを指定する。
- --globalvar-prefix=string
- テンプレートグローバル変数につけるプレフィックスを指定する。
使い方の例です。
- プレゼンテーションデータ(file1.html)をコンパイルして、出力用スクリプト(file1.php)に変換する。
ターゲット言語はeRuby。
$ kwartz -l eruby file1.html > file1.rhtml
- プレゼンテーションデータ(file1.html)とプレゼンテーションロジック(file1.plogic)から、出力用スクリプト(file1.php)を作成する。
ターゲット言語はPHP。
$ kwartz -l php -p file1.plogic file1.html > file1.php
- プレゼンテーションデータをPLプログラムにコンバートする。
$ kwartz -a convert file1.html | more
設定オプション
設定ファイルで、Kwartzのオプションを指定できます。 Kwartzの設定ファイルは、実装ごとに異なります。 Kwartz-rubyでは、kwartz/config.rbです。
設定ファイルでは、以下のオプションが設定できます。
- ESCAPE
- 自動サニタイズをデフォルトでオンにするか、オフにするかを指定します。
- NEWLINE
- 改行を表す文字列を指定します。 ただし、Kwartzは改行が「\n」か「\r\n」かを自動判別することができるので、通常は変更する必要はありません。
- INDENT
- インデントとして使う空白文字列を指定します。
- LOCALVAR_PREFIX
- テンプレートローカル変数のプレフィックス(頭につける文字列)を指定します。
- GLOBALVAR_PREFIX
- テンプレートグローバル変数のプレフィックス(頭につける文字列)を指定します。
- LANG
- デフォルトの出力用言語を指定します。
- ODD
-
トグル変数の奇数値を指定します。
「
id="FOREACH:var=list"
」と「id="LOOP:var=list"
」で使用されます。
- EVEN
-
トグル変数の偶数値を指定します。
「
id="FOREACH:var=list"
」と「id="LOOP:var=list"
」で使用されます。
- DATTR
-
ディレクティブで使用する属性名を指定します。デフォルトは
kw:d
です。
- NOEND
- 終了タグを必要としないタグ名のリストです。デフォルトは [ "input", "br", "meta", "img", "hr" ] です。
- DEFUN_CLASS
- コマンドラインオプション'-a defun'を使って関数を定義するときの、 デフォルトのクラス名またはモジュール名です。
- DEFUN_FUNCTION
- コマンドラインオプション'-a defun'を使って関数を定義するときの、 デフォルトの関数名またはメソッド名です。
- CHARSET
- 文字コードを指定します。出力用言語がjstl11、jstl10のときに使用されます。
- EMBED_PATTERN
- プレゼンテーションデータ中に式を埋め込むためのパターンを指定します。
- INCDIRS
-
「
include:
」ディレクティブで読み込むファイルを探すディレクトリを指定します。 デフォルトは [ "." ] つまりカレントディレクトリです。