Kwartz Users' Guide
last update: $Date: 2005-06-21 19:23:20 +0900 (Tue, 21 Jun 2005) $
Preface
This is the users' guide to Kwartz(*1), a template system which realized the concept of 'Separation of Presentation Logic and Presentation Data'(SoPL/PD) or 'Independence of Presenation Logic'(IoPL).
- (*1)
- Development of Kwartz had subsidized by Exploratory Software Project of IPA (Information-Technology Promotion Agency Japan).
Table of Contents
Introduction to Kwartz
What's Kwartz?
Kwartz(*2) is a template system which realized the concept of 'Separation of Presentation Logic and Presentaion Data'(SoPL/PD) or 'Independence of Presentation Logic'(IoPL).
Kwartz-ruby is an implemenation of Kwartz in Ruby. There is a plan to implement Kwartz in PHP or Java.
In the following, the word 'Kwartz' means the specification of the template system and the word 'Kwartz-ruby' means the implementation of it in Ruby language.
- (*2)
- 'Kwartz' is pronounced like 'Quartz'.
Features
Kwartz has the following features:
- Separates presentation logic from presentation data.
-
Using template systems such as Smarty, Velocity, XMLC, amrita, etc, you can separate HTML design from business logic as a template. With Kwartz, you can separate presentation logic from a template. In other words, Kwartz divides a template into 'presentation data' and 'presentation logic'. You need not mix presentation logic into HTML files nor main program.
- Very fast
-
Kwartz creates a script from a template (= presentation data and presentaion logic). All you have to do in main program is to call the output script. Because Kwartz doesn't use DOM trees or the like, it is both fast and light-weight.
- Multiple programing languages
-
Kwartz can create output scripts for Ruby(eRuby), PHP, JSP(JSTL 1.1 & 1.0), and Velocity from a template file, because Kwartz uses an internal intermediate language. You don't have to change the presentation layer at all, even if you changed programming language.
- Doesn't break HTML design at all
-
You must use directives like
{foreach ...}{/foreach}
in Smarty or#foreach(...)
in Jakarta Velocity. These directives break the HTML design of template. Kwartz doesn't break HTML design because Kwartz uses id attributes for marking in an HTML template. - Can handle any text file
-
Kwartz uses an original template parser; not using an HTML or XML parser, it is able to handle any text file (HTML, PostScript, RTF, and so on). This also means that Kwartz can handle non-well-formed XML files, as well as well-formed XML files. This is an advantage of Kwartz against Enhydra XMLC or amrita, which handle only XML/HTML files.
- Auto-Sanitizing and Partial-Sanitizing
-
Kwartz can do sanitizing automatically. You don't need to write '
CGI.escapeHTML(var)
' or 'htmlspecialchars($var)
'. You are free to turn sanitizing on/off, as well specifying which parts of the template to sanitize.
Simple Example
In Kwartz, a template is defined as both presentation data and presentation logic. They may be described in separate files.
This is an example of a presentation data file.
- '
id="list"
' means "I'll operate this element in presentation logic" (called 'marking' in Kwartz). - '
id="item"
' is also an marking.
Presentation data file(example1.html):
<table> <tr id="list"> <td id="item">foo</td> </tr> </table>
And the following is an example of presentation logic. In presentation logic, you can operate on elements which are marked in presentation data.
- '
#item { ... }
' represents an element marked with name 'item' (= '<td>...</td>').- '
value: expression;
' represents that the content of the element is replaced by value ofexpression
, which is value of a variablemember
in this case. - '
remove: "id";
' represents that the id attribute is to be deleted.
- '
- '
#list { ... }
' represents an element marked with name 'list' (= '<tr>...</tr>')- '
plogic: { ... }
' represents presentation logic of the element. - '
@stag
' represents a start tag (= '<tr>'). - '
@cont
' represents content(= '<td id="item">foo</td>'). - '
@etag
' represents an end tag(= '</tr>'). - '
foreach (var in list) { ... }
' represents an iteration.
- '
Presentation logic file(example1.plogic):
#item { // The element which is marked by 'id="item"' value: member; // replace the content with value of a variable 'member' remove: "id"; // remove the id attribte } #list { // The element which is marked by 'id="list"' remove: "id"; // remove the id attribute plogic: { // define the presentation logic foreach (member in member_list) { @stag; // start tag @cont; // content @etag; // end tag } } }
Kwartz creates output scripts automatically for eRuby, PHP, and JSP (JSTL 1.1&1.0) from the above two files. This action is called 'compiling'. To compile, enter one of the following commands:
### for eRuby $ kwartz -l eruby -p example1.plogic example1.html > example1.rhtml ### for PHP $ kwartz -l php -p example1.plogic example1.html > example1.php ### for JSTL 1.1 $ kwartz -l jstl11 -p example1.plogic example1.html > example1.jsp ### for JSTL 1.0 $ kwartz -l jstl10 -p example1.plogic example1.html > example1.jsp ### for Velocity $ kwartz -l velocity -p example1.plogic example1.html > example1.vm
The following is the output script for each respective language.
Output Script for eRuby(example1.rhtml):
<table> <% for member in member_list do %> <tr> <td><%= member %></td> </tr> <% end %> </table>
Output Script for PHP(example1.php):
<table> <?php foreach ($member_list as $member) { ?> <tr> <td><?php echo $member; ?></td> </tr> <?php } ?> </table>
Output Script for JSTL 1.1(*3)(example1.jsp):
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> <table> <c:forEach var="member" items="${member_list}"> <tr> <td><c:out value="${member}" escapeXml="false"/></td> </tr> </c:forEach> </table>
Output Script for JSTL1.0(example1.jsp):
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %> <table> <c:forEach var="member" items="${member_list}"> <tr> <td><c:out value="${member}" escapeXml="false"/></td> </tr> </c:forEach> </table>
Output Script for JSTL1.0(example1.jsp):
<table> #foreach($member in $member_list) <tr> <td>$!{member}</td> </tr> #end </table>
Using the command-line option '-e
' when compiling, Kwartz will output sanitized scripts.
For sanitizing, CGI.escapeHTML()
is used in eRuby, htmlspecialchars()
in PHP,
<c:out/>
without escapeXml="false"
in JSTL, $esc.html()
of EscapeTool in Velocity.
Then execute or import these output scripts into your main program, like this:
Main Program (Ruby) :
## set a data member_list = [ 'Oboro', 'Ominae', 'Jaquemonde' ] ## print out using ERB require 'erb' require 'cgi' # for sanitizing str = File.open('example1.rhtml') { |f| f.read() } str.untaint trim_mode = 1 erb = ERB.new(str, $SAFE, trim_mode) print erb.result(binding()) ## or print out using ERuby require 'eruby' require 'cgi' # for sanitizing ERuby::import('example1.rhtml')
Main Program (PHP) :
<?php // set a data $member_list = array('Oboro', 'Ominae', 'Jaquemonde'); // print out include('example1.php'); ?>
Main Program (JSTL) :
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ... // set a data java.util.List member_list = new java.util.ArrayList(); member_list.add("Oboro"); member_list.add("Ominae"); member_list.add("Jaquemonde"); // print RequestDispatcher dispatcher = request.getRequestDispatcher("example1.jsp"); dispatcher.include(request, response); // or dispatcher.forward(request, response); }
Main Program (Velocity) :
import org.apache.velocity.app.Velocity; import org.apache.velocity.VelocityContext; import org.apache.velocity.Template; import org.apache.velocity.exception.ResourceNotFoundException; import org.apache.velocity.exception.ParseErrorException; import org.apache.velocity.exception.MethodInvocationException; import java.io.OutputStreamWriter; import java.io.IOException; public class Main1 { public static void main(String[] args) { try { // initialization Velocity.init(); // create data java.util.List member_list = new java.util.ArrayList(); member_list.add("Oboro"); member_list.add("Ominae"); member_list.add("Jaquemonde"); // create context and set data VelocityContext context = new VelocityContext(); context.put("member_list", member_list); // read template and merge it with context Template template = Velocity.getTemplate("Test.vm", "UTF8"); OutputStreamWriter writer = new OutputStreamWriter(System.out); template.merge(context, writer); // print out writer.flush(); } catch (ResourceNotFoundException ex) { // template not found } catch (ParseErrorException ex) { // syntax error exists in template } catch (MethodInvocationException ex) { // method invocation violation } catch (IOException ex) { // I/O exepption } catch (Exception ex) { // other exception } }
Calling or executing the output script, you might get a web page like this:
<table> <tr> <td>Oboro</td> </tr> <tr> <td>Ominae</td> </tr> <tr> <td>Jaquemonde</td> </tr> </table>
- (*3)
- if you specify the command-line option '--charset=CHARSET', Kwartz will output
<%@ page contentType="text/html; charset=CHARSET" %>
when the language is JSTL.
Complex Example
The following is a little complex example which is borderd table.
Marking is done with id="mark:name"
instead of id="name"
in the following presentation data.
You don't have to write remove: "id"
in presentation logic file
because Kwartz removes id="mark:name"
automatically.
Presentation Data (example2.html):
<table> <tr bgcolor="#CCCCFF" id="mark:list"> <td id="mark:name">foo</td> <td> <a href="mailto:foo@mail.com" id="mark:email">foo@mail.com</a> </td> </tr> </table>
The following is the presentation logic file. In the presentation logic, you should detect whether odd or even line in the iteration.
Presentation Logic (example2.plogic):
// an element which is marked by 'id="mark:list"': // * print value of a variable 'color' as bgcolor attribute value. // * change value of a variable 'color' whether odd or even line. #list { attrs: "bgcolor" color; plogic: { i = 0; foreach (member in member_list) { i += 1; color = i % 2 == 0 ? '#FFCCCC' : '#CCCCFF'; @stag; // start tag @cont; // content @etag; // end tag } } } // an element which is marked by 'id="mark:name"': // * print value of member['name'] as content of the element. #name { value: member['name']; } // an element marked by 'id="mark:email"': // * print value of member['emal'] as contentn of the element. // * print "mailto:" and member['email'] as href attribute value. // (operator '.+' means string concatenation.) #email { value: member['email']; attrs: "href" ("mailto:" .+ member['email']); }
You will find that there is no HTML tag in the presentation logic and no logic in the presentation data. That is to say, Kwartz can separate presentation logic from presentation data.
Notice that you cannot write ctr++
because incremental operator (++
) is not supported.
Compile:
### for eRuby $ kwartz -l eruby -p example2.plogic example2.html > example2.rhtml ### for PHP $ kwartz -l php -p example2.plogic example2.html > example2.php ### for JSTL 1.1 $ kwartz -l jstl11 -p example2.plogic example2.html > example2.jsp ### for JSTL 1.0 $ kwartz -l jstl10 -p example2.plogic example2.html > example2.jsp ### for Velocity $ kwartz -l velocity -p example2.plogic example2.html > example2.vm
Output Script:
### for eRuby <table> <% i = 0 %> <% for member in member_list do %> <% i += 1 %> <% color = i % 2 == 0 ? "#FFCCCC" : "#CCCCFF" %> <tr bgcolor="<%= color %>"> <td><%= member["name"] %></td> <td> <a href="mailto:<%= member["email"] %>"><%= member["email"] %></a> </td> </tr> <% end %> </table> ### for PHP <table> <?php $i = 0; ?> <?php foreach ($member_list as $member) { ?> <?php $i += 1; ?> <?php $color = $i % 2 == 0 ? "#FFCCCC" : "#CCCCFF"; ?> <tr bgcolor="<?php echo $color; ?>"> <td><?php echo $member["name"]; ?></td> <td> <a href="mailto:<?php echo $member["email"]; ?>"><?php echo $member["email"]; ?></a> </td> </tr> <?php } ?> </table> ### for JSTL <table> <c:set var="i" value="0"/> <c:forEach var="member" items="${member_list}"> <c:set var="i" value="${i + 1}"/> <c:set var="color" value="${i % 2 eq 0 ? '#FFCCCC' : '#CCCCFF'}"/> <tr bgcolor="<c:out value="${color}" escapeXml="false"/>"> <td><c:out value="${member['name']}" escapeXml="false"/></td> <td> <a href="mailto:<c:out value="${member['email']}" escapeXml="false"/>"><c:out value="${member['email']}" escapeXml="false"/></a> </td> </tr> </c:forEach> </table> ### for Velocity <table> #set($i = 0) #foreach($member in $member_list) #set($i = $i + 1) #if($i % 2 == 0) #set($color = "#FFCCCC") #else #set($color = "#CCCCFF") #end <tr bgcolor="$!{color}"> <td>$!{member["name"]}</td> <td> <a href="mailto:$!{member["email"]}">$!{member["email"]}</a> </td> </tr> #end </table>
Other Examples of Presentation Logic
Kwartz enables you to write complex presentation logic natulally. This section shows some examples. See Presentation Pattern Catalog for details.
- You can choose to iterate an element.
#list { plogic: { foreach (member in member_list) { @stag; @cont; @etag; } } }
- You can choose to iterate only contents. This is useful for <dl></dl>.
#list { plogic: { @stag; foreach (member in member_list) { @cont; } @etag; } }
- You can print a value of a variable or an expression instead of a static content string.
#list { plogic: { @stag; print("Hello!"); @etag; } }
The following is equalt to the above.#list { value: "Hello!"; }
- You can print a value of a variable or an expression instead of an element.
#list { plogic: { print("<b>Hello!</b>"); } }
- You can delete the start tag and the end tag.
#list { plogic: { @cont; } }
- You can delete an element. This is useful for delete dummy data.
#list { plogic: { } }
- You can replace an element by other element marked.
#list { plogic: { @element(foo); // expand other element marked with name 'foo' } }
- You can replace content of element by other element marked.
#list { plogic: { @stag; @element(foo); // expand other element marked with name 'foo' @etag; } }
- You can include a complex presentation logic like this:
#list { plogic: { i = 0; foreach (member in member_list) { i += 1; // notice: i++ and ++i are unsupported if (i % 2 == 0) { color = 'red'; } else { color = 'blue'; } @stag; @cont; @etag; } }
It is very important that tag/attribute names don't appear in presentation logic at all. This way, you don't need to change presentation logic files even if the tag/attribute names are changed in the presentation data.
Kwartz separates presentation logic from presentation data.
Directives
Presentation logic may be embedded into presentation data in Kwartz. You can choose to separate or not to sepearate presentation data and presentation logic.
To embed presentation logic into presentation data, use directives. Directive is a command to embed presentation logic into presentation data. In Kwartz, 'id' and 'kw:d' attributes are used to describe directives.
The following is an example to use directives.
- Directive
id="foreach:var=list"
means to iterate the element. - Directive
id="value:expression"
means to print value of expression as content of the element. - Directive
id="dummy:str"
means that the element is a dummy and is not printed out. (Str is a string only to keep unique value of id attribute.) @{expression}@
(*4) is also a directive to print out expression value.
Presentation Data(example3.html):
<table> <tr id="foreach:member=member_list"> <td id="value:member['name']">foo</td> <td><a href="mailto:@{member['email']}@"> @{member['email']}@</a></td> </tr> <tr id="dummy:d1"> <td>bar</td> <td><a href="mailto:bar@mail.org">bar@mail.org</a></td> </tr> <tr id="dummy:d2"> <td>baz</td> <td><a href="mailto:baz@mail.net">baz@mail.net</a></td> </tr> </table>
Compile:
### for eRuby $ kwartz -l eruby example3.html > example3.rhtml ### for PHP $ kwartz -l php example3.html > example3.php ### for JSTL1.1 $ kwartz -l jstl11 example3.html > example3.jsp
Output script:
### for eRuby <table> <% for member in member_list do %> <tr> <td><%= member["name"] %></td> <td><a href="mailto:<%= member["email"] %>"> <%= member["email"] %></a></td> </tr> <% end %> </table> ### for PHP <table> <?php foreach ($member_list as $member) { ?> <tr> <td><?php echo $member["name"]; ?></td> <td><a href="mailto:<?php echo $member["email"]; ?>"> <?php echo $member["email"]; ?></a></td> </tr> <?php } ?> </table> ### for JSTL <table> <c:forEach var="member" items="${member_list}"> <tr> <td><c:out value="${member['name']}" escapeXml="false"/></td> <td><a href="mailto:<c:out value="${member['email']}" escapeXml="false"/>"> <c:out value="${member['email']}" escapeXml="false"/></a></td> </tr> </c:forEach> </table> ### for Velocity <table> #foreach($member in $member_list) <tr> <td>$!{member["name"]}</td> <td><a href="mailto:$!{member["email"]}"> $!{member["email"]}</a></td> </tr> #end </table>
There are several directives such as conditional branching. See reference manual for details.
- (*4)
- This pattern is editable with a constant EMBED_PATTERN in configuration file(kwartz/config.rb).
Sanitizing
Kwartz supports Automatic Sanitizing and Partially Sanitizing.
Automatic Sanitizing
-e
is the command-line optin to generate output script with sanitizing.
CGI.escapeHTML()
is used in eRuby for sanitizing, htmlspecialchars()
in PHP, <c:out/>
tag without escapeXml="false"
in JSTL, and $!esc.html()
in Velocity.
Presentation Data (sanitize1.html):
<tr bgcolor="@{color}@"> <td id="value:str">foo</td> </tr>
Compile:
### for eRuby $ kwartz -e -l eruby sanitize1.html > sanitize1.rhtml ### for ERB $ kwartz -e -l erb sanitize1.html > sanitize1.rhtml ### for PHP $ kwartz -e -l php sanitize1.html > sanitize1.php ### for JSTL $ kwartz -e -l jstl sanitize1.html > sanitize1.jsp ### for Velocity $ kwartz -e -l velocity sanitize1.html > sanitize1.vm
Output Scirpt:
### for eRuby <tr bgcolor="<%= CGI::escapeHTML((color).to_s) %>"> <td><%= CGI::escapeHTML((str).to_s) %></td> </tr> ### for ERB <tr bgcolor="<%=h(color)%>"> <td><%=h(str)%></td> </tr> ### for PHP <tr bgcolor="<?php echo htmlspecialchars($color); ?>"> <td><?php echo htmlspecialchars($str); ?></td> </tr> ### for JSTL <tr bgcolor="<c:out value="${color}"/>"> <td><c:out value="${str}"/></td> </tr> ### for Velocity <tr bgcolor="$!esc.html($color)"> <td>$!esc.html($str)</td> </tr>
Constant string and constant number are not sanitized.
Conditional expression such as 'flag ? " checked" : ""
' is not sanitized because the result is constant string whether the value of 'flag
' is true or false.
Partially Sanitizing
The function E(expr)
always sanitizes expression expr
even when '-e' is not specified.
The function X(expr)
doesn't sanitize expression expr
even when '-e' is specified.
(*5)
Presentaion Data:
<table> <tr bgcolor="@{X(color)}@"> <td id="value:E(str)">foo</td> </tr> </table>
Compile:
### for eRuby $ kwartz -e -l eruby sanitize1.html > sanitize1.rhtml ### for ERB $ kwartz -e -l erb sanitize1.html > sanitize1.rhtml ### for PHP $ kwartz -e -l php sanitize1.html > sanitize1.php ### for JSTL 1.1 $ kwartz -e -l jstl11 sanitize1.html > sanitize1.jsp ### for Velocity $ kwartz -e -l velocity sanitize1.html > sanitize1.vm
Output Script:
### for eRuby <table> <tr bgcolor="<%= color %>"> <td><%= CGI::escapeHTML((str).to_s) %></td> </tr> </table> ### for ERB <table> <tr bgcolor="<%= color %>"> <td><%=h(str)%></td> </tr> </table> ### for PHP <table> <tr bgcolor="<?php echo $color; ?>"> <td><?php echo htmlspecialchars($str); ?></td> </tr> </table> ### for JSTL <table> <tr bgcolor="<c:out value="${color}" escapeXml="false"/>"> <td><c:out value="${str}"/></td> </tr> </table> ### for Velocity <table> <tr bgcolor="$!{color}"> <td>$!esc.html($str)</td> </tr> </table>
Directives id="Value:expr"
and id="Attr:name=expr"
always sanitize expression expr
even when the sanitizing command-line option is not specified.
Directives id="VALUE:expr:"
and id="ATTR:name=expr"
doesn't sanitize expression expr
even when the sanitizing command-line option is specified.
These are equivalent to id="value:E(expr)"
, id="attr:name=E(expr)"
,
id="value:X(expr)"
, and id="attr:name=X(expr)"
.
- (*5)
- E() and X() are pseudo-function. They are not expression but allowed to appear as argument of print statement of PL. For example, '
@{E(...)}@
' and 'id="value:E(...)
' are valid, but 'id="set:str=E(...)"
' is invalid.
Configuration for sanitizing
File 'kwartz/config.rb' is a configuration file for Kwartz-ruby.
If you want to sanitize in default, change value of constant ESCAPE
to true in the configuration file.
Other Topics
Restrictions
Kwartz parses presentation data file by regular expression pattern matching. It means that Kwartz doesn't use HTML parser nor XML parser for parsing presentation data. This approach enables Kwartz to handle any type of text file, and also brings the following restrictions to Kwartz.
- Cannot omit end tag if id attribute is specified.
<!-- Kwartz cannot parse the following because </li> is omitted. --> <ul> <li id="foo">foo </ul>
An Element which doesn't have any content is to be written as an empty tag such as<foo id="..."/>
.
- However,
<input>
,<br>
,<meta>
,<img>
, and<hr>
are allowed to omit end tag. And these doesn't have to be written as an empty tag.<!-- </input/> is omitted but Kwartz can parse correctly. --> <input type="text" name="user" id="user">
Constant NOEND lists these tag names in file kwartz/config.rb. Upper-case and lower-case are distinguished.
- Attribute values should be surrounded with '
"
'.<!-- Kwartz fails parsing because attribute value is not surrounded with '"'. --> <h1 id="value:title" class=title>title</h1>
Analyzing Global and Local Variables
Kwartz have a function to analyze presentation data/logic files and inspect variables.
In Kwartz, variables are called 'template global variables' if they are set in the main program and are passed to output script. Variables are called 'template local variables' if they are used only in the template. Kwartz have a function to detect whether variables are template global or local and report the result.
Assume the following presentation data and presentation logic:
Presentation Data (analyze.html):
<span kw:d="value:title">Analyzer Example</span> <dl id="mark:items"> <dt kw:d="value:ctr"></dt> <dd kw:d="value:item">Foo</dd> </dl>
Presentation Logic (analyze.plogic):
#items { plogic: { @stag; ctr = 0; foreach (item in list) { ctr += 1; @cont; } @etag; } }
In this case, variables ctr
and item
are template local variables because they are used only in the template.
Variables title
and list
are template global variables because they are set in the main program and passed to output script.
Invoking kwartz with the command-line option -a analyze
reports template global or local variables.
Analyzing Example:
$ kwartz -a analyze -p analyze.plogic analyze.html Global: title list Local: ctr item
Rename Template Global/Local Variable Names
The command-line option --globalvar-prefix=prefix
and --localvar-prefix=prefix
add a prefix to global/local variable names in template.
In Ruby or PHP, for example, if template local variables in templates have the same name of variables in main program, assignment into template local variables effects the control of main program. To avoid this confliction, you should add a prefix such as '_' to template local variable names automatically.
The following is the example using 'analyze.html' and 'analyze.plogic' shown in the previous section.
Compile:
$ kwartz -l eruby -p analyze.plogic --localvar-prefix='_' analyze.html $ kwartz -l php -p analyze.plogic --localvar-prefix='_' analyze.html $ kwartz -l jstl11 -p analyze.plogic --localvar-prefix='_' analyze.html $ kwartz -l velocity -p analyze.plogic --localvar-prefix='_' analyze.html
Output Script:
### for eRuby <%= title %> <dl> <% _ctr = 0 %> <% for _item in list do %> <% _ctr += 1 %> <dt><%= _ctr %></dt> <dd><%= _item %></dd> <% end %> </dl> ### for PHP <?php echo $title; ?> <dl> <?php $_ctr = 0; ?> <?php foreach ($list as $_item) { ?> <?php $_ctr += 1; ?> <dt><?php echo $_ctr; ?></dt> <dd><?php echo $_item; ?></dd> <?php } ?> </dl> ### for JSTL <c:out value="${title}" escapeXml="false"/> <dl> <c:set var="_ctr" value="0"/> <c:forEach var="_item" items="${list}"> <c:set var="_ctr" value="${_ctr + 1}"/> <dt><c:out value="${_ctr}" escapeXml="false"/></dt> <dd><c:out value="${_item}" escapeXml="false"/></dd> </c:forEach> </dl> ### for Velocity $!{title} <dl> #set($_ctr = 0) #foreach($_item in $list) #set($_ctr = $_ctr + 1) <dt>$!{_ctr}</dt> <dd>$!{_item}</dd> #end </dl>
Constant GLOBALVAR_PREFIX and LOCALVAR_PREFIX in configuration file specifies the default prefix.
Span Tag Deletion
The span tags which contains only directives are regarded as dummy tags and deleted automatically.
Presentation Data:
<h1><span id="mark:title">title</span></h1> Hello <span id="value:user">World</span>!
Presentation Logic:
#title { value: title; }
Output Script(for eRuby):
<h1><%= title %></h1> Hello <%= user %>!
The span tags are not removed when they have other attributes.
Presentation Data:
<h1><span id="mark:title" class="title">title</span></h1> Hello <span kw:d="value:user" style="color:black">World</span>!
Output Script(for eRuby):
<h1><span class="title"><%= title %></span></h1> Hello <span style="color:black"><%= user %></span>!
Appending Expression to Start Tag
The following is an example to print only attribute variable such as <input type="..." checked>
.
Presentation Data:
<input type="checkbox" name="foo" value="Y" id="foo" />
Presentation Logic:
#foo { append: flag ? ' checked' : ''; }
Output Script:
### for eRuby <input type="checkbox" name="foo" value="Y" id="foo"<%= flag ? " checked" : "" %> /> ### for PHP <input type="checkbox" name="foo" value="Y" id="foo"<?php echo $flag ? " 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" %> <input type="checkbox" name="foo" value="Y" id="foo"<c:out value="${flag ? ' checked' : ''}" escapeXml="false"/> /> ### for JSTL 1.0 <%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %> <c:choose><c:when test="${flag}"> <input type="checkbox" name="foo" value="Y" id="foo" checked /> </c:when><c:otherwise> <input type="checkbox" name="foo" value="Y" id="foo" /> </c:otherwise></c:choose> ### for Velocity #if($flag) <input type="checkbox" name="foo" value="Y" id="foo" checked /> #else <input type="checkbox" name="foo" value="Y" id="foo" /> #end
A directive append(expr)
appends the value of the expression expr
in the element tag.
Presentation Data:
<input type="checkbox" name="foo" value="Y" id="append:flag?' checked':''" />
There are useful functions to print checked="checked"
or selected="selected"
easily.
C(expr)
, S(expr)
, D(expr)
prints
checked="checked"
, selected="selected"
, disabled="disabled"
respectively
when the expression expr
is true.
Presentation Data:
<input type="checkbox" name="foo" value="Y" id="foo" />
Presentation Logic:
#foo { append: C(foo == 100); }
Output Script:
### for eRuby <input type="checkbox" name="foo" value="Y" id="foo"<%= foo == 100 ? " checked=\"checked\"" : "" %> /> ### for PHP <input type="checkbox" name="foo" value="Y" id="foo"<?php echo $foo == 100 ? " checked=\"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" %> <input type="checkbox" name="foo" value="Y" id="foo"<c:out value="${foo eq 100 ? ' checked="checked"' : ''}" escapeXml="false"/> /> ### for JSTL 1.0 <%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %> <c:choose><c:when test="${foo eq 100}"> <input type="checkbox" name="foo" value="Y" id="foo" checked="checked" /> </c:when><c:otherwise> <input type="checkbox" name="foo" value="Y" id="foo" /> </c:otherwise></c:choose> ### for Velocity #if($foo == 100) <input type="checkbox" name="foo" value="Y" id="foo" checked="checked" /> #else <input type="checkbox" name="foo" value="Y" id="foo" /> #end
Describe Presentation Logic in Target Language
Kwartz allows you to write presentation logics in target language (such as Ruby, PHP, Java, etc).
<%= expression %>
or<?= expression ?>
means expression in target language.<% statement %>
or<? statement ?>
means statement in target language. Semicolon(`;
') is not needed after%>
and?>
.
Presentation Logic(eRuby):
#foo { value: <%= str.empty? ? "null" : str %>; plogic: { @stag; <% ENV.each do |name, value| %> @cont; <% end %> @etag; } }
Presentation Logic(PHP):
#foo { value: <?= $str === NULL ? "null" : str ?>; plogic: { @stag; <?php foreach ($_ENV as $name => $value) { ?> @cont; <?php } ?> @etag; } }
Kwartz just print code in <%= ... %>
and <% ... %>
and doesn't parse or analyze it.
Therefore Kwartz doesn't report syntax error in the target code
nor report analyzing template local/global variables.
Write X(<%= expression %>)
if you don't want to sanitize expression.
Kwartz with Ruby on Rails
Kwartz-ruby has a special option -Rails
for Ruby on Rails.
It is equivarent to -l erb --globalvar-prefix='@'
.
If you want to use Rails-specific functions such as link_to()
or url_for()
,
use <% ... %>
or <%= ... %>
(or embed them into presentation data file).
Presentation Data (list.html)
<html> <body> <h1>Online Cookbook - All Recipes</h1> <table border="1"> <tr> <th width="80%">Recipe</th> <th width="20%">Date</th> </tr> <tr id="mark:recipes"> <td><a href="..." id="mark:recipe_title">Hot Chips</a></td> <td id="mark:recipe_date">2004 November 11</td> </tr> <tr id="dummy:d1"> <td><a href="...">Ice Water</a></td> <td>2004 November 11</td> </tr> </table> <p> <a href="..." id="mark:recipe_new">Create new recipe</a> </p> </body> </html>
Presentation Logic (list.plogic)
#recipes { plogic: { foreach (recipe in recipes) { @stag; // start tag @cont; // content @etag; // end tag } } } #recipe_title { value: recipe.title; attrs: "href" <%= url_for(:action => "show", :id => recipe.id) %>; } // Or // #recipe_title { // plogic: { // print(<%= link_to recipe.title, :action => "show", :id => recipe.id %>); // } // } #recipe_date { value: recipe.date; } #recipe_new { attrs: "href" <%= url_for(:action => "new") %>; } // Or // #recipe_new { // plogic: { // print(<%= link_to "Create new recipe", :action => "new" %>); // } // }
Compile:
$ kwartz -Rails -p list.plogic list.html > list.rhtml
Output Script:
<html> <body> <h1>Online Cookbook - All Recipes</h1> <table border="1"> <tr> <th width="80%">Recipe</th> <th width="20%">Date</th> </tr> <% for recipe in @recipes do %> <tr> <td><a href="<%= url_for(:action => "show", :id => recipe.id) %>"><%= recipe.title %></a></td> <td><%= recipe.date %></td> </tr> <% end %> </table> <p> <a href="<%= url_for(:action => "new") %>">Create new recipe</a> </p> </body> </html>
Write X(<%= expression %>)
if you don't want to sanitize expression.
Compile Template into a Function of Ruby or PHP
Using the command-line option '-a defun
', you can compile templates into a function of Ruby or PHP.
Presentation Data (hoge1.html)
Hello @{user}@ ! <ul id="mark:list"> <li id="value:item">xxx</li> </ul>
Presentation Logic (hoge1.plogic)
#list { plogic: { @stag; foreach (item in list) { @cont; } @stag; } }
Compile:
$ kwartz -l eruby -a defun -p hoge1.plogic hoge1.html > hoge1.rb $ kwartz -l php -a defun -p hoge1.plogic hoge1.html > hoge1.php
Output Script:
### for eRuby def view_hoge1(__args) user = __args[:user] list = __args[:list] return _view_hoge1(user,list) end def _view_hoge1(user,list) _erbout = ''; _erbout << "Hello "; _erbout <<(( user ).to_s); _erbout << " !\n" _erbout << "<ul>\n" for item in list do _erbout << " <li>"; _erbout <<(( item ).to_s); _erbout << "</li>\n" end _erbout << "<ul>\n" _erbout end ### for PHP <?php function view_hoge1($__args) { $user = $__args['user'] $list = $__args['list'] return _view_hoge1($user, $list) } function _view_hoge1($user, $list) { ob_start(); ?>Hello <?php echo $user; ?> ! <ul> <?php foreach ($list as $item) { ?> <li><?php echo $item; ?></li> <?php } ?> <ul> <?php $__s = ob_get_contents(); ob_end_clean(); return $__s; } ?>
Two functions are defined by '-a defun' option. You can use whichever you prefer.
view_filename()
- a function which takes arguments by a hash object._view_filename()
- a function which takes arguments explicitly.
You can specify funtion or method name with the command-line option '-F name
',
class or module name with '-C name
', and arguments with '-A arg1,arg2,...
'.
The constant DEFUN_CLASS and DEFUN_FUNCTION in configuration file also enables you to set
default class/module name and default function/method name.