Kwartz User's Guide

Makoto Kuwata <kwa(at)kuwata-lab.com>
last update: $Date: 2004/05/09 14:25:20 $

Preface

This is a user's guide of Kwartz(*1), a template system for web-designer and web-programmer.

Sorry for my poor English. You may need imagination and patience to read this document.

(*1)
Development of Kwartz is subsidized by Exploratory Software Project of IPA (Information-Technology Promotion Agency Japan).

Table of Contents

Table of Contents:

Changelog

2004-05-09
  • "..." is also string literal, in addition to '...'.
  • auto-detect "\n" or "\r\n".
  • command line option "--delete_idattr" which delete id attribute from presentation data.
2004-04-23
  • new language ruby2 and php2
  • updated about 'mkmethod'
2004-04-04
  • utility script 'mkmethod'
  • tips to get result as string
  • fixed 'import()' => 'include()' in PHP
2004-04-01
  • 'include' directive.
  • 'load' directive and :load() statement.
  • function E() and X()
2004-03-21
  • delete only <span> tag and leave <div> tag
2004-03-20
  • special macro BEGIN and END
  • Ruby sanitizing
2004-03-19
  • new command option '--enable_eruby=true'
  • new keyword 'empty'
  • new action 'analyze'
  • new directive notation 'id="foreach:item:list"'
2004-03-13
  • use id attribute instead of kd attribute.
  • add description about new features (id="replace:name" and :value(name=expr))
  • add new samples (navilink, breadcrumbs, error messages, calendar)
2004-03-08
  • subsection 'Compare with null explicitly' added.
  • some eratta fixed
2004-02-27
  • 'Notes' of directives and presentaion language updated
  • description about sanitizing updated
2004-02-24
  • some eratta fixed
2004-02-12
  • public release


About Kwartz

What's Kwartz?

Kwartz(*2) is a template system, implemented in Ruby. It has following features:

Separate presentation logic from presentation data.

Using any template system such as Velocity, XMLC, Amrita, etc, you can separate HTML desgin 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 don't need to mix presentation logic into HTML file nor main program.

Very fast

Kwartz creates a script for the output 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 tree or so, Kwartz works very fast, and light-weight.

Multi programing language

Kwartz can create outputs script for Ruby, PHP, JSP and eRuby from a template file, because Kwartz uses an intermediate language internally. You don't have to change the presentation layer at all, even if you changed programming language. Kwartz supports the following language: Ruby, PHP, JSP, eRuby, ERB, Velocity

Doesn't break HTML design at all

You must use directives like '#foreach(...)' in Jakarta Velocity or '[FOREACH ...]' in Template-Toolkit. These directives break HTML design of template. Kwartz doesn't break HTML design at all because Kwartz uses tag's attributes for marking in HTML template.

Can handle any text file

Kwartz uses an original template parser, not using XML parser, so as to enable to handle any text file (HTML, PostScript, RTF, and so on). It means that Kwartz can handle invalid-formed XML files, as well as well-formed XML files. It is an advantage of Kwartz against Enhydra XMLC or amrita, which handle only XML/HML files.

Auto-Sanitizing Supported

Kwartz can do sanitizing automatically. You don't need to write 'CGI.escapeHTML(var)' or 'htmlspecialchars($var)'. You are free to make sanitizing on/off, and can specify a certain part of template to sanitize or unsanitize.

(*2)
Pronounced same as 'Quartz'.

Simple Example

In Kwartz, you should define a template as presentation data and presentation logic. They are described in separate files.

This is a sample of presentation data file.

Presentation data file(example.html):

<table>
  <tr id="xxx">
    <td>#{var}#</td>
  </tr>
</table>

And the following is a sample of presentation logic. In presentation logic, you can operate elements which are marked in presentation data.

Presentation logic file(example.plogic):

## Re-define an element to iterate start tag, content and end tag.
:elem(xxx)		## element
  :foreach(var=list)
    @stag		## start tag
    @cont		## content
    @etag		## end tag
  :end
:end

Kwartz creates output scripts automatically for Ruby, PHP, JSP, eRuby, ERB and Velocity from the above two files. This action is called 'Compile'. To compile, enter the following command:

### for Ruby
$ kwartz -l ruby  -p example.plogic example.html > example.rb
or
$ kwartz -l ruby2 -p example.plogic example.html > example.rb2

### for PHP
$ kwartz -l php   -p example.plogic example.html > example.php
or
$ kwartz -l php2  -p example.plogic example.html > example.php2

### for JSP
$ kwartz -l jsp   -p example.plogic example.html > example.jsp

### for eRuby
$ kwartz -l eruby -p example.plogic example.html > example.rthml

### for ERB
$ kwartz -l erb   -p example.plogic example.html > example.erb

### for Velocity
$ kwartz -l velocity -p example.plogic example.html > example.vm

The following is the output script for each language.

for Ruby (example.rb) :

print "<table>\n"
for var in list do
  print "  <tr id=\"xxx\">\n"
  print "    <td>", var, "</td>\n"
  print "  </tr>\n"
end
print "</table>\n"

for Ruby (example.rb2) -- get output as string:

_s << "<table>\n"
for var in list do
  _s << "  <tr id=\"xxx\">\n"
  _s << "    <td>" << (var).to_s << "</td>\n"
  _s << "  </tr>\n"
end
_s << "</table>\n"

for PHP (example.php) :

<table>
<?php foreach ($list as $var) { ?>
  <tr id="xxx">
    <td><?php echo $var; ?></td>
  </tr>
<?php } ?>
</table>

for PHP (example.php2) -- get output as string:

<?php  ob_start(); ?>
<table>
<?php foreach ($list as $var) { ?>
  <tr id="xxx">
    <td><?php echo $var; ?></td>
  </tr>
<?php } ?>
</table>
<?php  $_s = ob_get_contents();  ob_end_clean(); ?>

for JSP(*3)(example.jsp) :

<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<table>
<c:forEach var="var" items="${list}">
  <tr id="xxx">
    <td><c:out value="${var}" escapeXml="false"/></td>
  </tr>
</c:forEach>
</table>

for eRuby(example.rhtml) :

<table>
<% for var in list do
 %>  <tr id="xxx">
    <td><%= var %></td>
  </tr>
<% end
 %></table>

for ERB(example.erb) :

<table>
% for var in list do
  <tr id="xxx">
    <td><%= var %></td>
  </tr>
% end
</table>

for Velocity(example.vm) :

<table>
#foreach ($var in $list)
  <tr id="xxx">
    <td>$!{var}</td>
  </tr>
#end
</table>

Using command-line option -s when compiling, kwartz will output sanitized scripts (except Velocity). For sanitizing, htmlspecialchars() is used in PHP, CGI.escapeHTML() in Ruby and eRuby, html_escape() in ERB, <c:out/> without escapeXml="false" in JSP.

Then execute or import these output script in your main-program, like this:

Main program(ruby) :

require 'cgi'        # for sanitizing
s = File.open('example.rb') { |f| f.read }
s.untaint            # for CGI program
eval s

Main program(ruby2) :

require 'cgi'        # for sanitizing
s = File.open('example.rb2') { |f| f.read }
s.untaint            # for CGI program
_s = ''
eval s
print _s

Main program(php) :

<?php
   include('example.php');
 ?>

Main program(php2) :

<?php
   include('example.php2');
   echo $_s;
 ?>

Main program (jsp) :

public void doGet(HttpServletRequest request,
                  HttpServletResponse response)
                  throws ServletException, IOException {
   ...
   RequestDispatcher dispatcher = 
       request.getRequestDispatcher('example.jsp');
   dispatcher.include(request, response);
   // or dispatcher.forward(request, response);
}

Main program(eruby) :

require 'eruby'
require 'cgi'        # for sanitizing
ERuby::import('example.rhtml')

Main program(erb) :

require 'erb'
include ERB::Util    # for sanitizing
s = File.open('example.erb') { |f| f.read }
s.untaint            # for CGI program
erb = ERB.new(s, $SAFE, '%')
erb.run(binding())   # or print erb.result(binding())

Main program(velocity) :

Velocity.init();
VelocityContext context = new VelocityContext();
Template template = Velocity.getTemplate("example.vm");
OutputStreamWriter writer = new OutputStreamWriter(System.out);
template.merge(context, writer);
writer.flush();

Calling or executing output scripts, you can get web page like this:

<table>
  <tr id="xxx">
    <td>apple</td>
  </tr>
  <tr id="xxx">
    <td>orange</td>
  </tr>
  <tr id="xxx">
    <td>banana</td>
  </tr>
</table>

You may mind that id attributes are appeared in each <tr></tr>. You can delete it from web page if you write it as id="mark:xxx" (which is equivalent to id="xxx" but it removes id attribute itself), or add command line option --delete_idattr=true.

In addition, you can 'embed' presentation logic into presentation data in Kwartz. You can select 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' or 'kd' attributes are used to describe directives.

The following is a sample of 'embedding' presentation logic into presentation data. This sample is compiled into the same output as the script files in above. .

<table>
  <tr id="foreach:var=list">
    <td id="value:var">foo</td>
  </tr>
</table>
(*3)
if you specify a command line option '--charset=CHARSET', kwartz will output <%@ page contentType="text/html; charset=CHARSET" %> when JSP.


How Kwartz works

Presentation data

Kwartz separates presentation layer into 'presentation data' and 'presentation logic' with the following approach.

It is called 'marking' to mark a region which you want to change or replace in the presentation data. You can do 'marking' with attribute 'id' or 'kd'(*4), like id="name".

Example of marking:

<table>
 <tr id="list">
  <td>#{item}#</td>
 </tr>
</table>

Kwartz recognizes only marked elements, and regard unmarked elements as a normal plain texts. It means that Kwartz can handle any type of text, including not well-formed XML file.

Example of 'not well-formed XML file':

<span id="test">
 aaa <bbb> ccc </ddd>
</span>
(*4)
The attribute name is derived from 'Kwartz Directive'. You can change the name of attribute with command-line option --attr_name.

Intermediate code

Kwartz 'converts' presentation data into intermediate code.

When converting a presentation data into intermeidate code, Kwartz creates four macros for each marked elements.

Here is a sample of presentation data:

<table>
 <tr id="list">
  <td>#{item}#</td>
 </tr>
</table>

Kwartz will convert the presentation data into the following intermediate code. You'll find that four macros are defined and presentation data is described with these macros.

:macro(stag_list)          ## start tag
  :print(" <tr id=\"list\">\n")
:end

:macro(cont_list)          ## content
  :print("  <td>", item, "</td>\n")
:end

:macro(etag_list)          ## end tag
  :print(" </tr>\n")
:end

:macro(elem_list)          ## element
  :expand(stag_list)            ## expand a macro
  :expand(cont_list)            ## expand a macro
  :expand(etag_list)            ## expand a macro
:end

:print("<table>\n")        ## presentation data
:expand(elem_list)              ## expand macro
:print("</table>\n")

'id="list"' will be left in intermediate code. If you want to delete it, use 'id="mark:list"' instead, or add command line option --delete_idattr=true

Intermediate code is described in an itermediate language. The language is named 'PL'(Presentation Language).


Presentation Logic

Presentation logic is:

The following is a sample of presentation logic. This sample will overwrite macro 'elem_list' to iterate from start tag to end tag.

:macro(elem_list)
  :foreach(item=itemlist)    ## iteration with foreach statement
    :expand(stag_item)       ## start tag
    :expand(cont_item)       ## content
    :expand(etag_item)       ## end tag
  :end
:end

And you can write the above presentation logic as the following. Kwartz parser will treat it as the same code as the above.

:elem(list)                  ## same as :macro(elem_item) 
  :foreach(item=itemlist)
    @stag                    ## same as :expand(stag_item)
    @cont                    ## same as :expand(cont_item)
    @etag                    ## same as :eppand(etag_item)
  :end
:end

Output script

Kwartz merges intermediate code and presentation logic, then expands macros and transforms it into an output script. This action is called 'translation'.

This is a sample of translation.

   
   :print("<table>\n")
   :expand(elem_list)
   :print("</table>\n")

      |
      | expand macros
      V

   :print("<table>\n")
   :foreach(item=itemlist)
     :expand(stag_list)
     :expand(cont_list)
     :expand(etag_list)
   :end
   :print("</table>\n")

      |
      | expand macros
      V

   :print("<table>\n")
   :foreach(item=itemlist)
     :print(" <tr id=\"list\">\n")
     :print("  <td>", item, "</td>\n")
     :print(" </tr>\n")
   :end
   :print("</table>\n")

      |
      | output script for each langague
      V

   ### for Ruby
   print "<table>\n"
   for item in itemlist do
     print " <tr id=\"list\">\n"
     print "  <td>", item, "</td>\n"
     print " </tr>\n"
   end
   print "</table>\n"
 
   ### for PHP
   <table>
   <?php foreach($itemlist as $item) { ?>
    <tr id="list">
     <td><?php echo $item; ?></td>
    </tr>
   <?php } ?>
   </table>

   ### for JSP
   <table>
   <c:forEach var="item" items="${itemlist}">
    <tr id="list">
     <td><c:out value="${item}"/></td>
    </tr>
   </c:forEach>
   </table>

   ### for eRuby
   <table>
   <% for item in itemlist do
    %> <tr id="list">
     <td><%= item %></td>
    </tr>
   <% end
    %></table>

   ### for ERB
   <table>
   % for item in itemlist do
    <tr id="list">
     <td><%= item %></td>
    </tr>
   % end
   </table>

   ### for Velocity
   <table>
   #foreach ($item in $itemlist)
    <tr id="list">
     <td>${item}</td>
    </tr>
   #end
   </table>

The remarking task is to call or execute these output scripts in main program.

These are the all what Kwartz does.


How to call or execute output script

The way to call or execute output script is different for each language. See other documents for detail.

in Ruby:

Read and eval output file. You have to require cgi.rb when sanitiginz.

require 'cgi'         # for sanitizing
str = File.open('example.rb') { |f| f.read }
str.untaint           # for CGI program
eval str

Or if you specified command line option `-l ruby2' :

require 'cgi'         # for sanitizing
str = File.open('example.rb') { |f| f.read }
str.untaint           # for CGI program
_s = ''
eval str
print _s
in PHP:

Use include() function.

<?php include('example.phtml'); ?>

Or if you specified command line option `-l php2' :

<?php include('example.phtml'); echo $_s; ?>
in JSP (Servlet):

Use RequestDispatcher#forward() or RequestDispatcher#include().

RequestDispatcher dispatcher = 
    request.getRequestDispatcher("example.jsp");
dispatcher.forward(request, response);
in eRuby:

Use ERuby::import() when using eruby. You have to require cgi.rb when sanitiginz.

require 'eruby'
require 'cgi'         # for sanitizing
ERuby::import('example.rhtml')
in ERB:

Use ERB#run() when using ERB. You should specify '%' as trim parameter when creating ERB object. And you have to impoort ERB::Util when sanitizing.

require 'erb'
include ERB::Util     # for sanitizing
str = File.open('example.erb') { |f| f.read }
str.untaint
erb = ERB.new(str, $SAFE, '%')
erb.run(binding())   # or print erb.result(binding())
in Velocity:

Use org.apache.velocity.context.Context, org.apache.velocity.Template, and so on. See Velocity's manual for details.

Velocity.init();
VelocityContext context = new VelocityContext();
Template template = Velocity.getTemplate("example.vm");
OutputStreamWriter writer = new OutputStreamWriter(System.out);
template.merge(context, writer);
writer.flush();

Other examples of presentation logic

An example described in the previous section is to iterate from start tag to end tag. This section shows some other examples.

It is very important that tag/attribute names don't appear in presentation logic at all. In other words, you don't need to change presentaion logic files even if the tag/attribute name is changed in the presesntation data.

It means that Kwartz separates presentation logic from presentation data.


Conclution

This is a chart of a process which represents how Kwartz works. In this chart, with '*' represents a file which is created automatically, Without '*' represents a file which have to be created manually by a developer.

  Presentation Data           Presentation Logic
    (HTML)                    (intermediate language)
       |                            |
       | convert                    |
       |                            |
       V                            |
Intermediate Code*                  |
(intermediate language)             |
       |                            |
       |                            |
       +-------------+--------------+
                     | translate
                     |
                     V              call/import
              Output Program*    <============ Main Program
           (Ruby/PHP/JSP/eRuby)             (Ruby/PHP/JSP/eRuby)
                     |
                     | output
                     |
                     V
                 Web Page*
                  (HTML)

Following files are created by a developer manually:

Kwartz creates automatically:

Term:

convert
To transform presentation data into intermediate code
translate
To transform intermeidate code and presentation logic into output script.
compile
'Convert' and 'translate', that is, transform presentation data and presenstaion logics into an output script.


Directive

What is directive?

Kwartz allows presentation logics to embedded in presentation data. Commands for that purpose is called 'directive'.

'Directive' is a set of commands to embed presentation logics into presentation data. Marking (id="name" or id="mark:name") is also directive. There are several directives for iteration, conditional branch, and so on.

Kwartz uses 'id' or/and 'kd' attribute to embed directives in presentation data ('kd' means 'Kwartz Directive'). Usually id attribute is used, but if you want to use id attribute for other purpose you can use kd attribute instead of id attribute. And you can use both id and kd attribute in a tag. See 'Id and kd attributes' for detail about id and kd attribute.

You may have a question: It is the most important feature of Kwartz that Kwartz separates presentation logics from presentation data. Why does Kwartz allow to embed presentation logics into presentation data?

The answer is 'to make it possible for developers to choose either approaches.' In other words, to increase option of development style. Kwartz doesn't force you to use one approach. Separate presentation logic and presentation data if you like to separate them, or mix them up if you like.

You may wonder that Kwartz becomes a ordinary template system if presentation logic is embedded into presentation data. But Kwartz has the following merits compared to other template system.


Marking

Directive id="name" or id="mark:name" marks an element. 'Marking' is to mark an element with a name name. The marked element is described as a macro in intermediate code.

Presentation Data:

<li id="item">foo</li>

Intermediate Code:

:macro(stag_item)
  :print("<li id=\"item\">")
:end

:macro(cont_item)
  :print("foo")
:end

:macro(etag_item)
  :print("</li>\n")
:end

:macro(elem_item)
  :expand(stag_item)
  :expand(cont_item)
  :expand(etag_item)
:end

:expand(elem_item)

Output Program:

### Ruby
print "<li id=\"item\">"
print "foo"
print "</li>\n"

### PHP
<li id="item">foo</li>

### JSP + JSTL
<li id="item">foo</li>

### eRuby
<li id="item">foo</li>

### ERB
<li id="item">foo</li>

### Velocity
<li id="item">foo</li>

The difference between 'id="name"' and 'id="mark:name"' is that the former is leaved but the latter is removed when compiling into intermediate code.

Presentation Data:

<li id="mark:item">foo</li>

Intermediate Code:

:macro(stag_item)
  :print("<li>")
:end

:macro(cont_item)
  :print("foo")
:end

:macro(etag_item)
  :print("</li>\n")
:end

:macro(elem_item)
  :expand(stag_item)
  :expand(cont_item)
  :expand(etag_item)
:end

:expand(elem_item)

Print value of expression

#{/expression/}# is a directive which prints the value of expression. It is equivarent to 'print expression' in Ruby, or '<?php echo expression; ?>' in PHP.

Presentation Data:

Hello #{user}#!

Intermediate Code:

:print("Hello ", user, "!\n")

Output Program:

### Ruby
print "Hello ", user, "!\n"

### PHP
Hello <?php echo $user; ?>!

### JSP + JSTL
Hello <c:out value="${user}" escapeXml="false"/>!

### eRuby
Hello <%= user %>!

### ERB
Hello <%= user %>!

### Velocity
Hello $!{user}!

Expression is sanitized if you specified command option -s (or --escape=true) when compiling template. Notice that only expressions except constant string and constant number are sanitized.

Output Program (with command option -s) :

### Ruby
print "Hello ", CGI.escapeHTML((user).to_s), "!\n"

### PHP
Hello <?php echo htmlspecialchars($user); ?>!

### JSP + JSTL
Hello <c:out value="${user}"/>!

### eRuby
Hello <%= CGI.escapeHTML((user).to_s) %>!

### ERB
Hello <%= html_escape(user) %>!

### Velocity
Hello $!{user}!

Using function E() or X(), you can specify sanitizing on/off for each expressions. E(expr) means that expression expr is sanitized and X(expr) means that expr is not sanitized. These are not effected by command option -s (or --escape=true).

Presentation Data:

With sanitizing:    #{E(expr)}#!
Without sanitizing: #{X(expr)}#!

Intermediate Code:

:print("With sanitizing:    ", E(expr), "\n")
:print("Without sanitizing: ", X(expr), "\n")

Output Program:

### Ruby
print "With sanitizing:    ", CGI.escapeHTML((expr).to_s), "!\n"
print "Without sanitizing: ", expr, "!\n"

### PHP
With sanitizing:    <?php echo htmlspecialchars($expr); ?>!
Without sanitizing: <?php echo $expr; ?>!

### JSP + JSTL
With sanitizing:    <c:out value="${expr}"/>!
Without sanitizing: <c:out value="${expr}" escapeXml="false"/>!

### eRuby
With sanitizing:    <%= CGI.escapeHTML((expr).to_s) %>!
Without sanitizing: <%= expr %>!

### ERB
With sanitizing:    <%= html_escape(expr) %>!
Without sanitizing: <%= expr %>!

### Velocity
With sanitizing:    $!{expr}!
Without sanitizing: $!{expr}!

Print value of expression 2

id="value:expression" is a directive to print the value of expression instead of the content. It is more suitable for HTML design than #{expression}#, because it allows to use dummy data.

Presentation Data:

<li id="value:hash['name']">foo</li>

Intermediate Code:

:print("<li>", hash['name'], "</li>\n")

Output Program:

### Ruby
print "<li>", hash["name"], "</li>\n"

### PHP
<li><?php echo $hash['name']; ?></li>

### JSP + JSTL
<li><c:out value="${hash['name']}" escapeXml="false"/></li>

### eRuby
<li><%= hash['name'] %></li>

### ERB
<li><%= hash['name'] %></li>

### Velocity
<li>$!{hash.get('name')}</li>

Using id="Value:expr, you can specify to sanitize expression. And using id="VALUE:expr, you can specify not to sanitize expression. These are equal to id="value:E(expr) or id="value:X(expr).


Attribute value

id="attr:name=value" (or id="attr:name:value") is a directive to set an attribute value. It overwrites existing value if attribute name is setted.

In the following example, attribute 'class' has a dummy value 'odd', and the actual value is derived from a variable 'klass'.

Presentation Data:

<tr class="odd" id="attr:class=klass">
  <td>foo</td>
</tr>

Intermediate Code:

:print("<tr class=\"", klass, "\">\n")
:print("  <td>foo</td>\n")
:print("</tr>\n")

Output Program:

### Ruby
print "<tr class=\"", klass, "\">\n"
print "  <td>foo</td>\n"
print "</tr>\n"

### PHP
<tr class="<?php echo $klass; ?>">
  <td>foo</td>
</tr>

### JSP + JSTL
<tr class="<c:out value="${klass}" escapeXml="false"/>">
  <td>foo</td>
</tr>

### eRuby
<tr class="<%= klass %>">
  <td>foo</td>
</tr>

### ERB
<tr class="<%= klass %>">
  <td>foo</td>
</tr>

### Velocity
<tr class="$!{klass}">
  <td>foo</td>
</tr>

Using id="Attr:name=value, you can specify to sanitize value. And using id="ATTR:name=value, you can specify not to sanitize value. These are equal to id="attr:name=E(value) or attr:name=X(value).

Separating with ';', you can list several attr:name=value directives in one id attribute, or list with other directive.

Presentation Data:

<font id="if:message;attr:class=klass;attr:bgcolor=color">
 #{message}#
</font>

Intermediate Code:

:if(message)
  :print("<font class=\"", klass, "\" bgcolor=\"", color, "\">\n")
  :print(" ", message, "\n")
  :print("</font>\n")
:end

Assign

id="set:var=value (or id="set:var:value) is directive for assigning value into a variable. Not only '=' but also '+=', '-=', '*=', '/=', '.+=' are available. ('.+=' means string concatination.)

Presentation Data:

<dt id="set:var=value">foo</dt>
<dd id="set:count+=1">123</dd>

Intermediate Code:

:set(var=value)
:print("<dt>")
:print("foo")
:print("</dt>\n")
:set(count+=1)
:print("<dd>")
:print("123")
:print("</dd>\n")

Output Program:

### Ruby
var = value
print "<dt>"
print "foo"
print "</dt>\n"
count += 1
print "<dd>"
print "123"
print "</dd>\n"

### PHP
<?php $var = $value; ?>
<dt>foo</dt>
<?php $count += 1; ?>
<dd>123</dd>

### JSP + JSTL
<c:set var="var" value="${value}"/>
<dt>foo</dt>
<c:set var="count" value="${count + 1}"/>
<dd>123</dd>

### eRuby
<% var = value
 %><dt>foo</dt>
<% count += 1
 %><dd>123</dd>

### ERB
% var = value
<dt>foo</dt>
% count += 1
<dd>123</dd>

### Velocity
#set ($var = $value)
<dt>foo</dt>
#set ($count = $count + 1)
<dd>123</dd>

Conditional branch

id="if:expression" is a directive for conditional branch. It enables only if-statement, cannot represent 'else' or 'else if'. If you want to use 'else' or 'else if', you should describe then in presentation logic file.

Presentation Data:

<font color="red" id="if:flag_error">
 Error!!
</font>

Intermediate Code:

:if(flag_error)
  :print("<font color=\"red\">\n")
  :print(" Error!!\n")
  :print("</font>\n")
:end

Output Program:

### Ruby
if flag_error then
  print "<font color=\"red\">\n"
  print " Error!!\n"
  print "</font>\n"
end

### PHP
<?php if ($flag_error) { ?>
<font color="red">
 Error!!
</font>
<?php } ?>

### JSP + JSTL
<c:choose>
<c:when test="${flag_error}">
<font color="red">
 Error!!
</font>
</c:when>
</c:choose>

### eRuby
<% if flag_error then
 %><font color="red">
 Error!!
</font>
<% end
 %>

### ERB
% if flag_error then
<font color="red">
 Error!!
</font>
% end

### Velocity
#if ($flag_error)
<font color="red">
 Error!!
</font>
#end

Iteration(foreach)

id="foreach:var=list" (or id="foreach:var=list") is a directive for iteration, with assignment each value of list into a variable.

Presentation Data:

<tr id="foreach:user=user_list">
  <td>#{user}#</td>
</tr>

Intermediate Code:

:foreach(user = user_list)
  :print("<tr>\n")
  :print("  <td>", user, "</td>\n")
  :print("</tr>\n")
:end

Output Program:

### Ruby
for user in user_list do
  print "<tr>\n"
  print "  <td>", user, "</td>\n"
  print "</tr>\n"
end

### PHP
<?php foreach ($user_list as $user) { ?>
<tr>
  <td><?php echo $user; ?></td>
</tr>
<?php } ?>

### JSP + JSTL
<c:forEach var="user" items="${user_list}">
<tr>
  <td><c:out value="${user}" escapeXml="false"/></td>
</tr>
</c:forEach>

### eRuby
<% for user in user_list do
 %><tr>
  <td><%= user %></td>
</tr>
<% end
 %>

### ERB
% for user in user_list do
<tr>
  <td><%= user %></td>
</tr>
% end

### Velocity
#foreach ($user in $user_list)
<tr>
  <td>$!{user}</td>
</tr>
#end

Iteration(list)

id="list:variable=list_expr" (or id="list:variable:list_expr") is a directive for iteration. It iterates only contents. Start tag and end tag are not iterated.

Presentation Data:

<tr id="list:user=user_list">
  <td>#{user}#</td>
</tr>

Intermediate Code:

:print("<tr>\n")
:foreach(user = user_list)
  :print("  <td>", user, "</td>\n")
:end
:print("</tr>\n")

Output Program:

### Ruby
print "<tr>\n"
for user in user_list do
  print "  <td>", user, "</td>\n"
end
print "</tr>\n"

### PHP
<tr>
<?php foreach ($user_list as $user) { ?>
  <td><?php echo $user; ?></td>
<?php } ?>
</tr>

### JSP + JSTL
<tr>
<c:forEach var="user" items="${user_list}">
  <td><c:out value="${user}" escapeXml="false"/></td>
</c:forEach>
</tr>

### eRuby
<tr>
<% for user in user_list do
 %>  <td><%= user %></td>
<% end
 %></tr>

### ERB
<tr>
% for user in user_list do
  <td><%= user %></td>
% end
</tr>

### Velocity
<tr>
#foreach ($user in $user_list)
  <td>$!{user}</td>
#end
</tr>

Iteration with count

id="Foreach:var=list" and id="List:var=list" are directives for iteration with loop counting. Counter variable name is var_ctr. Counter starts with 1.

Presentation Data:

<tr id="Foreach:item=item_list">
  <td id="value:item_ctr">1</td>
  <td id="value:item">foo</td>
</tr>

Intermediate Code:

:set(item_ctr = 0)
:foreach(item = item_list)
  :set(item_ctr += 1)
  :print("<tr>\n")
  :print("  <td>", item_ctr, "</td>\n")
  :print("  <td>", item, "</td>\n")
  :print("</tr>\n")
:end

Output Program:

### Ruby
item_ctr = 0
for item in item_list do
  item_ctr += 1
  print "<tr>\n"
  print "  <td>", item_ctr, "</td>\n"
  print "  <td>", item, "</td>\n"
  print "</tr>\n"
end

### PHP
<?php $item_ctr = 0; ?>
<?php foreach ($item_list as $item) { ?>
  <?php $item_ctr += 1; ?>
<tr>
  <td><?php echo $item_ctr; ?></td>
  <td><?php echo $item; ?></td>
</tr>
<?php } ?>

### JSP + JSTL
<c:set var="item_ctr" value="0"/>
<c:forEach var="item" items="${item_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>

### eRuby
<% item_ctr = 0
 %><% for item in item_list do
 %><% item_ctr += 1
 %><tr>
  <td><%= item_ctr %></td>
  <td><%= item %></td>
</tr>
<% end
 %>

### ERB
% item_ctr = 0
% for item in item_list do
%   item_ctr += 1
<tr>
  <td><%= item_ctr %></td>
  <td><%= item %></td>
</tr>
% end

### Velocity
#set ($item_ctr = 0)
#foreach ($item in $item_list)
  #set ($item_ctr = $item_ctr + 1)
<tr>
  <td>$!{item_ctr}</td>
  <td>$!{item}</td>
</tr>
#end

Iteration with toggle switch

id="FOREACH:var=list" and id="FOREACH:var=list" are directives for iteration with toggle-switching. Toggle-switch's value is changed if loop counter is odd or even. Variable Name of toggle-switch is var_tgl. Value of toggle-switch is 'odd' and 'even' by default. You can change them with command-line option --odd_value and --even_value.

Presentation Data:

<table>
  <tbody id="LIST:item=item_list">
    <tr class="#{item_tgl}#">
      <td id="value:item">foo</td>
    </tr>
  </tbody>
</table>

Intermediate Code:

:print("<table>\n")
:print("  <tbody>\n")
:set(item_ctr = 0)
:foreach(item = item_list)
  :set(item_ctr += 1)
  :set(item_tgl = item_ctr % 2 == 0 ? 'even' : 'odd')
  :print("    <tr class=\"", item_tgl, "\">\n")
  :print("      <td>", item, "</td>\n")
  :print("    </tr>\n")
:end
:print("  </tbody>\n")
:print("</table>\n")

Output Program:

### Ruby
print "<table>\n"
print "  <tbody>\n"
item_ctr = 0
for item in item_list do
  item_ctr += 1
  item_tgl = (item_ctr % 2 == 0 ? "even" : "odd")
  print "    <tr class=\"", item_tgl, "\">\n"
  print "      <td>", item, "</td>\n"
  print "    </tr>\n"
end
print "  </tbody>\n"
print "</table>\n"

### PHP
<table>
  <tbody>
<?php $item_ctr = 0; ?>
<?php foreach ($item_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>

### JSP + JSTL
<table>
  <tbody>
<c:set var="item_ctr" value="0"/>
<c:forEach var="item" items="${item_list}">
 <c:set var="item_ctr" value="${item_ctr + 1}"/>
 <c:choose>
<c:when test="${item_ctr % 2 == 0}">
  <c:set var="item_tgl" value="even"/>
 </c:when>
 <c:otherwise>
  <c:set var="item_tgl" value="odd"/>
 </c:otherwise>
 </c:choose>
    <tr class="<c:out value="${item_tgl}" escapeXml="false"/>">
      <td><c:out value="${item}" escapeXml="false"/></td>
    </tr>
</c:forEach>
  </tbody>
</table>

### eRuby
<table>
  <tbody>
<% item_ctr = 0
 %><% for item in item_list do
 %><% item_ctr += 1
 %><% item_tgl = (item_ctr % 2 == 0 ? 'even' : 'odd')
 %>    <tr class="<%= item_tgl %>">
      <td><%= item %></td>
    </tr>
<% end
 %>  </tbody>
</table>

### ERB
<table>
  <tbody>
% item_ctr = 0
% for item in item_list do
%   item_ctr += 1
%   item_tgl = (item_ctr % 2 == 0 ? 'even' : 'odd')
    <tr class="<%= item_tgl %>">
      <td><%= item %></td>
    </tr>
% end
  </tbody>
</table>

### Velocity
<table>
  <tbody>
#set ($item_ctr = 0)
#foreach ($item in $item_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>

Iteration (while)

id="while:expression" is a directive to iterate, with while-statement. Assignment is not expression in Kwartz, except in while-condition.

Kwartz will cause error when compiling while-statemnt into JSP or Velocity, because there is no custom tags in JSTL or Velocity's directive which is equvalent to while-statment.

Presentation Data:

<tr id="while:row=sth.fetch">
  <td>#{row[0]}#</td>
</tr>

Intermediate Code:

:while(row=sth.fetch)
  :print("<tr>\n")
  :print("  <td>", row[0], "</td>\n")
  :print("</tr>\n")
:end

Output Program:

### Ruby
while row = sth.fetch do
  print "<tr>\n"
  print "  <td>", row[0], "</td>\n"
  print "</tr>\n"
end

### PHP
<?php while ($row = $sth->fetch) { ?>
<tr>
  <td><?php echo $row[0]; ?></td>
</tr>
<?php } ?>

### eRuby
<% while row = sth.fetch do
 %><tr>
  <td><%= row[0] %></td>
</tr>
<% end
 %>

### ERB
% while row = sth.fetch do
<tr>
  <td><%= row[0] %></td>
</tr>
% end

Dummy data

id="dummy:name" is a directive fore ignoring an element. You should specify a unique string(*5) in name. name is a string to make different id attribute value in a XML/HTML document. You cannot specify same string in a document.

Presentation Data:

<tr id="dummy:d1">
  <td>bar</td>
</tr>
<tr id="dummy:d2">
  <td>baz</td>
</tr>

Intermediate Code:

                          ## Nothing

Output Program:

                          ## Nothing
(*5)
The string have no effectivity nor meaning.

Replacement of Element

'id="replace:name"' replaces an element with other element which is marked with name name.

Presentation Data:

<html>
  <body>
    <!-- breadclumbs navigation -->
    <span id="breadclumbs">
      <a href="/">Home</a>
      &gt; <a href="/ruby">Ruby</a>
      &gt; <a href="/ruby/kwartz">Kwartz</a>
    </span>

   ....

    <span id="replace:breadclumbs">
      Home &gt; Ruby &gt; Kwartz
    </span>
  </body>
</html

Intermediate Code:

:macro(stag_breadclumbs)
  :print("    <span id=\"breadclumbs\">\n")
:end

:macro(cont_breadclumbs)
  :print("      <a href=\"/\">Home</a>\n")
  :print("      &gt; <a href=\"/ruby\">Ruby</a>\n")
  :print("      &gt; <a href=\"/ruby/kwartz\">Kwartz</a>\n")
:end

:macro(etag_breadclumbs)
  :print("    </span>\n")
:end

:macro(elem_breadclumbs)
  :expand(stag_breadclumbs)
  :expand(cont_breadclumbs)
  :expand(etag_breadclumbs)
:end

:print("<html>\n")
:print("  <body>\n")
:print("    <!-- breadclumbs navigation -->\n")
:expand(elem_breadclumbs)

   ....

:expand(elem_breadclumbs)
:print("  </body>\n")
:print("</html\n")

Include presentation data file

id="include:'filename'" directive reads and includes other presentation data file (HTML file). Usually, <span/> tag is used such as <span id="include:'filename'"/>. (In Kwartz, <span> tags which contain only directives are deleted automatically.)

Presentation Data(tab.html) :

<span style="border-width:1 1 0 1; border-style:solid; padding:1 5 1 5">
  <a href="#{tab['url']}#" id="value:tab['name']" style="text-decoration:none">TabName</a>
</span>

Presentation Data(tab-main.html) :

<div id="foreach:tab:tablist">
  <span id="include:'tab.html'"/>
</div>

Intermediate Code:

:foreach(tab = tablist)
  :print("<div>\n")
  ## :print("  <span>")
  :print("<span style=\"border-width:1 1 0 1; border-style:solid; padding:1 5 1 5\">\n")
  :print("  <a href=\"", tab['url'], "\" style=\"text-decoration:none\">", tab['name'], "</a>\n")
  :print("</span>\n")
  ## :print("</span>\n")
  :print("</div>\n")
:end

Presentation data files included are to be placed in other directory. You can specify directories with a command line option --include_path=dir1,dir2,....

$ kwartz --include_path=dir1,dir2 tab-main.html

Load presentation logic file

id="load:'filename'" directive reads and includes other presentation data file (HTML file). Usually, <span/> tag is used such as <span id="load:'filename'"/>. (In Kwartz, <span> tags which contain only directives are deleted automatically.)

Usually, file name of presentation logic is specified by command line option(-p or -P). load directive is equal to these comamnd line options. In other words, you can specify file name of presentation logic with load directive as well as command line options. And load directive is avairable with command line options.

load directive should be at the end of presentation data file. Otherwise, presentation logic loaded may be overwritten by presentation data file.

Presentation Logic (load-lib.plogic) :

:elem(item)
  :foreach(item=itemlist)
    @stag
    @cont
    @etag
  :end
:end

:macro(BEGIN)
  :print("<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n")
  :print("<html lang=\"en\">\n")
  :print(" <body bgcolor=\"#FFFFFF\">\n")
:end

:macro(END)
  :print(" </body>\n")
  :print("<html>\n")
:end

Presentation Data(load-main.html) :

<ul id="mark:itemlist">
  <li id="value:item">foobar</li>
</ul>
<span id="load:'load-lib.plogic'"/>

Intermediate Code:

:macro(stag_itemlist)
  :print("<ul>\n")
:end

:macro(cont_itemlist)
  :print("  <li>", item, "</li>\n")
:end

:macro(etag_itemlist)
  :print("</ul>\n")
:end

:macro(elem_itemlist)
  :expand(stag_itemlist)
  :expand(cont_itemlist)
  :expand(etag_itemlist)
:end

:expand(elem_itemlist)
## :print("<span>")
:load('load-lib.plogic')
## :print("</span>\n")

Output Program:

### Ruby
print "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n"
print "<html lang=\"en\">\n"
print " <body bgcolor=\"\#FFFFFF\">\n"
print "<ul>\n"
print "  <li>", item, "</li>\n"
print "</ul>\n"
print " </body>\n"
print "<html>\n"

### PHP
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html lang="en">
 <body bgcolor="#FFFFFF">
<ul>
  <li><?php echo $item; ?></li>
</ul>
 </body>
<html>

### JSP + JSTL
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html lang="en">
 <body bgcolor="#FFFFFF">
<ul>
  <li><c:out value="${item}" escapeXml="false"/></li>
</ul>
 </body>
<html>

### eRuby
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html lang="en">
 <body bgcolor="#FFFFFF">
<ul>
  <li><%= item %></li>
</ul>
 </body>
<html>

### ERB
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html lang="en">
 <body bgcolor="#FFFFFF">
<ul>
  <li><%= item %></li>
</ul>
 </body>
<html>

### Velocity
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html lang="en">
 <body bgcolor="#FFFFFF">
<ul>
  <li>$!{item}</li>
</ul>
 </body>
<html>

Presentation data files loaded are to be placed in other directory. You can specify directories with a command line option --load_path=dir1,dir2,....

$ kwartz --load_path=dir1,dir2 load-main.html

Id and kd attributes


Notes

There are some notes to use directives.



PL -- Presentation Language

Kwartz uses intermeidate language internally. The intermediate language is named PL(Presentation Language). PL is used for two purpose in Kwartz:

In fact, Kwartz describe presentation data and presentation logic in PL.

This section shows how to write PL program.

Comment

Characters coming after '#' in a line is a comment. You should use '##' instead of '#', because '#*' or '#@' may have special functions in the future.

## comment

String

"..." or '...' represents string literal. The former can contain special char: line feed (\n), carriage return (\r) or tab (\t).

'foo bar'		## String
"foo bar\n"		## String which contains line feed character

Boolean and null

Keywords true, false, null are available in expression.

:set(flag = obj == null? true : false)

true, false and null are translated to proper keywords in each language.

Translation of true, false and null
Language name true false null
Ruby,eRuby,ERB true false nil
PHP TRUE FALSE NULL
JSP(JSTL) true false null
Velocity true false -

Translation a PL program which contains keyword null into Velocity script will cause error, because Velocity doesn't have a keyword null. But Kwartz will translate 'expr==null' and 'expr!=null' to '!expr' and 'expr' when translating into Velocity.

PL Program:

:set(flag = obj == null? true : false)

:if (expr != null)
  :print("expr is not null.\n")
:else
  :print("epxr is null.\n")
:end

Output Script:

### Velocity
#if (! $obj)
  #set ($flag = true)
#else
  #set ($flag = false)
#end
#if ($expr)
expr is not null.
#else
epxr is null.
#end

Variable

A variable starts with alphabet or '_', and follows with alphabet or number or '_'.

You don't need to decrare variable, nor specify it's type(*6).

(*6)
Because of this feature, it is very difficult to support "static language" in Kwartz.

Operator

There are several operators. Comparable operator is available for number and string(*7).

Comparable operator == != < <= > >=
Logical operator && || !
Arithmetic operator + - * / %
String Concatenation operator .+
Conditional operator ?:

Conditional Operator is available in Ruby, eRuby, ERB and PHP. But it is not available in JSP (to be exact, in expression language of JSTL) and Velocity. Therefore, conditional operator will be translated to if-statement in JSP or Velocity.

PL Program:

:set(color = ctr%2==0 ? '#CCCCFF' : '#FFCCCC')

Output Script:

### Ruby
color = (ctr % 2 == 0 ? "\#CCCCFF" : "\#FFCCCC")

### PHP
<?php $color = ($ctr % 2 == 0 ? '#CCCCFF' : '#FFCCCC'); ?>

### JSP + JSTL
<c:choose>
<c:when test="${ctr % 2 == 0}">
 <c:set var="color" value="#CCCCFF"/>
</c:when>
<c:otherwise>
 <c:set var="color" value="#FFCCCC"/>
</c:otherwise>
</c:choose>

### eRuby
<% color = (ctr % 2 == 0 ? '#CCCCFF' : '#FFCCCC')
 %>

### ERB
% color = (ctr % 2 == 0 ? '#CCCCFF' : '#FFCCCC')

### Velocity
#if ($ctr % 2 == 0)
  #set ($color = '#CCCCFF')
#else
  #set ($color = '#FFCCCC')
#end
(*7)
It is very difficult to support Perl in Kwartz, because Perl have different operator for number and String (like '==' and 'eq', '!=' and 'ne', ...).

Print

:print(...) is a print statement. Any expression can be in print statement.

PL Program:

:print('foo', bar, "baz\n")   ## print a string and value of a variable

Output Script:

### Ruby
print "foo", bar, "baz\n"

### PHP
foo<?php echo $bar; ?>baz

### JSP + JSTL
foo<c:out value="${bar}" escapeXml="false"/>baz

### eRuby
foo<%= bar %>baz

### ERB
foo<%= bar %>baz

### Velocity
foo$!{bar}baz

When you make auto-sanitizing enabled, the output scripts of Ruby, PHP, eRuby and ERB will be the following:

### Ruby
print "foo", CGI.escapeHTML((bar).to_s), "baz\n"

### PHP
foo<?php echo htmlspecialchars($bar); ?>baz

### eRuby
foo<%= CGI.escapeHTML((bar).to_s) %>baz

### ERB
foo<%= html_escape(bar) %>baz

Assignment

':set(var=value)' is an assignment statement. Spaces around '(' or '=' are allowed.

Also '+=', '-=', '*=', '/=', '%=' and '.+=' are allowed. '.+=' means string concatination.

PL Program:

:set(name = 'Foo')      ## assign a string 'Foo' into variable
:set(count += 1)        ## increment value of variable
:set(str .+= '.txt')    ## append a string

Output Script:

### Ruby
name = "Foo"
count += 1
str << ".txt"

### PHP
<?php $name = 'Foo'; ?>
<?php $count += 1; ?>
<?php $str .= '.txt'; ?>

### JSP + JSTL
<c:set var="name" value="Foo"/>
<c:set var="count" value="${count + 1}"/>
<c:set var="str" value="${str}${'.txt'}"/>

### eRuby
<% name = 'Foo'
 %><% count += 1
 %><% str << '.txt'
 %>

### ERB
% name = 'Foo'
% count += 1
% str << '.txt'

### Velocity
#set ($name = 'Foo')
#set ($count = $count + 1)
#set ($str = "${str}.txt")

Array and Hash

You can refer an array as arr[expr]. Also you can refer a hash in the same way.(*8).

PL Program:

:set(list[n] = 10)         ## assign into n-th element of array
:print(list[i], "\n")      ## print  i-th element of array
:set(hash['key'] = 'foo')  ## assign into a hash element
:print(hash['key'])        ## print a hash element

Output Script:

### Ruby
list[n] = 10
print list[i], "\n"
hash["key"] = "foo"
print hash["key"]

### PHP
<?php $list[$n] = 10; ?>
<?php echo $list[$i]; ?>
<?php $hash['key'] = 'foo'; ?>
<?php echo $hash['key']; ?>

### JSP + JSTL
<c:set var="list[n]" value="10"/>
<c:out value="${list[i]}" escapeXml="false"/>
<c:set var="hash['key']" value="foo"/>
<c:out value="${hash['key']}" escapeXml="false"/>

### eRuby
<% list[n] = 10
 %><%= list[i] %>
<% hash['key'] = 'foo'
 %><%= hash['key'] %>

### ERB
% list[n] = 10
<%= list[i] %>
% hash['key'] = 'foo'
<%= hash['key'] %>

### Velocity
#set ($list.get($n) = 10)
$!{list.get($i)}
#set ($hash.key = 'foo')
$!{hash.get('key')}

You can also refer a hash as 'hash[:key]'. 'key' must be a string which is constructed only with alphabet, number or '_'.

'hash[:key]' will be translated according to target programming language:

Target language Result of translation
Ruby, eRuby, ERB hash[:key]
PHP $hash['key']
JSP hash['key']
Velocity hash.key

PL Program:

:set(hash[:key] = 'foo')
:print(hash[:key])

Output Script:

### Ruby
hash[:key] = "foo"
print hash[:key]

### PHP
<?php $hash['key'] = 'foo'; ?>
<?php echo $hash['key']; ?>

### JSP + JSTL
<c:set var="hash['key']" value="foo"/>
<c:out value="${hash['key']}" escapeXml="false"/>

### eRuby
<% hash[:key] = 'foo'
 %><%= hash[:key] %>

### ERB
% hash[:key] = 'foo'
<%= hash[:key] %>

### Velocity
#set ($hash.key = 'foo')
$!{hash.key}
(*8)
Operators for array and hash are same, therefore it is difficult to support a language, say Perl, which use different operator for array and hash.

Property

You can refer a property of an object as 'object.property'. Property is not a method, so property cannot accept any arguments.

There is no way to create a new object nor define a new class in PL. These tasks must be done in main program.

PL Program:

:print(user.name)

Output Script:

### Ruby
print user.name

### PHP
<?php echo $user->name; ?>

### JSP + JSTL
<c:out value="${user.name}" escapeXml="false"/>

### eRuby
<%= user.name %>

### ERB
<%= user.name %>

### Velocity
$!{user.name}

Iteration

:foreach(variable=value_list) ... :end represents iteration, known as foreach statement. Each item in an array list is assigned into variable var in iteration.

PL Program:

:foreach(item = list)
  :print(item, "\n")
:end

Output Script:

### Ruby
for item in list do
  print item, "\n"
end

### PHP
<?php foreach ($list as $item) { ?>
<?php echo $item; ?>
<?php } ?>

### JSP + JSTL
<c:forEach var="item" items="${list}">
<c:out value="${item}" escapeXml="false"/>
</c:forEach>

### eRuby
<% for item in list do
 %><%= item %>
<% end
 %>

### ERB
% for item in list do
<%= item %>
% end

### Velocity
#foreach ($item in $list)
$!{item}
#end

You can also use while-statment. Kwartz will cause an error if you translate while-statement into JSP or Velocity script, because there is no JSTL custom tag or Velocity directive which are equvalent to while-statment.

PL Program:

:set(i = 0)
:while(i < length)
  :print(list[i])
  :set(i += 1)
:end

Output Script:

### Ruby
i = 0
while i < length do
  print list[i]
  i += 1
end

### PHP
<?php $i = 0; ?>
<?php while ($i < $length) { ?>
<?php echo $list[$i]; ?><?php $i += 1; ?>
<?php } ?>

### eRuby
<% i = 0
 %><% while i < length do
 %><%= list[i] %><% i += 1
 %><% end
 %>

### ERB
% i = 0
% while i < length do
<%= list[i] %>
%   i += 1
% end

for-statement (like C or Java) is not available.


Conditional branch

':if(condition) ... :elsif(condition) ... :else ... :end' represents conditional branch.

PL Program:

:if(ctr % 2 == 0)         ## if even
  :set(klass='even')      ## then assign a string 'even'
:else                     ## else
  :set(klass='odd')       ## assign a string 'odd'
:end

Output Script:

### Ruby
if ctr % 2 == 0 then
  klass = "even"
else
  klass = "odd"
end

### PHP
<?php if ($ctr % 2 == 0) { ?>
  <?php $klass = 'even'; ?>
<?php } else { ?>
  <?php $klass = 'odd'; ?>
<?php } ?>

### JSP + JSTL
<c:choose>
<c:when test="${ctr % 2 == 0}">
 <c:set var="klass" value="even"/>
</c:when>
<c:otherwise>
 <c:set var="klass" value="odd"/>
</c:otherwise>
</c:choose>

### eRuby
<% if ctr % 2 == 0 then
 %><% klass = 'even'
 %><% else
 %><% klass = 'odd'
 %><% end
 %>

### ERB
% if ctr % 2 == 0 then
%   klass = 'even'
% else
%   klass = 'odd'
% end

### Velocity
#if ($ctr % 2 == 0)
  #set ($klass = 'even')
#else
  #set ($klass = 'odd')
#end

Macro

':macro(macro_name) ... :end' represents a macro definition. ':expand(macro_name)' or '@macro_name' represents a macro expantion.

The following is a sample of macro definition and expantion. It represents start tag, content and end tag of an element '<li>#{item}#</li>'.

## macro definition
:macro(stag_item)
  :print("<li>")
:end

:macro(cont_item)
  :print(item)
:end

:macro(etag_item)
  :print("</li>")
:end

## macro expantion (it is equivalent to '<li>#{item}#</li>')
:expand(stag_item)
:expand(cont_item)
:expand(etag_item)

Macro expantion can be in macro definition.

## macro definition
:macro(stag_item)
  :print("<li>")
:end

:macro(cont_item)
  :print(item)
:end

:macro(etag_item)
  :print("</li>")
:end

:macro(elem_item)    ## macro definition containing macro expantion
  :expand(stag_item)
  :expand(cont_item)
  :expand(etag_item)
:end

## equivalent to '<li>#{item}#</li>'
:expand(elem_item)

Special syntax for defining macro of an element is available. The syntax is only for element macro definition.

## Macro definition for an element
:elem(item)
  @stag
  @cont
  @etag
:end

## Above is equal to the following
:macro(elem_item)
  :expand(stag_item)
  :expand(cont_item)
  :expand(etag_item)
:end

You can use '@stag', '@cont' and '@etag' only in :elem() .. :end. Using them in :macro() .. :end will be error.

## NG
:macro(elem_item)	## must be ':elem(item)'
  @stag
  @cont
  @etag
:end

Kwartz provides a special syntax to define a macro of content of elements. It is equivalent to a directive id="value:expr".

## replace content of element with epxression value
:value(item = expr)

## above is equal to the following
:macro(cont_item)
  :print(expr)
:end

Macro cannt accept any arguments.


Macro BEGIN and END

'BEGIN' and 'END' are special macros. If you define them, you can add codes at beginning/end of the output script.

Presentation data:

  Hello <span id="value:user">World</span>!

PL Program:

:macro(BEGIN)
  :print("<html>\n")
  :print(" <body>\n")
:end
:macro(END)
  :print(" </body>\n")
  :print("</html>\n")
:end

Output script:

### Ruby
print "<html>\n"
print " <body>\n"
print "  Hello "
print user
print "!\n"
print " </body>\n"
print "</html>\n"

### PHP
<html>
 <body>
  Hello <?php echo $user; ?>!
 </body>
</html>

Function

You can use the following two functions in PL.

E(expr)
Sanitize expression expr. Sanitizing is done even when command line option for sanitizing is not specified.
X(expr)
Don't sanitize expression expr, even when command line options for sanitizing is specified.

Currently, you cannot define or use any function except above two.


Empty

'empty' is a keyword in order to check whether value is null or empty string. It can be praced only at the right-side of == or != operator.

PL Program:

:if (str1 == empty)
  :print("str1 is empty.\n")
:elsif(str2 != empty)
  :print("str2 is not empty.\n")
:end

Output Script:

### Ruby
if (str1 == nil || str1 == "") then
  print "str1 is empty.\n"
elsif (str2 != nil && str2 != "") then
  print "str2 is not empty.\n"
end

### PHP
<?php if (! $str1) { ?>
str1 is empty.
<?php } elseif ($str2) { ?>
str2 is not empty.
<?php } ?>

### JSP + JSTL
<c:choose>
<c:when test="${(empty str1)}">
str1 is empty.
</c:when>
<c:when test="${!(empty str2)}">
str2 is not empty.
</c:when>
</c:choose>

### eRuby
<% if (str1 == nil || str1 == '') then
 %>str1 is empty.
<% elsif (str2 != nil && str2 != '') then
 %>str2 is not empty.
<% end
 %>

### ERB
% if (str1 == nil || str1 == '') then
str1 is empty.
% elsif (str2 != nil && str2 != '') then
str2 is not empty.
% end

### Velocity
#if ((! $str1 || $str1 == ''))
str1 is empty.
#elseif (($str2 && $str2 != ''))
str2 is not empty.
#end

Load presentation logic file

:load('filename') loads other presentation logic file. You can specify directories at where files are placed by command line option --load_path=dir1,dir2,....

PL Program:

:load('file.plogic')

:load() can load only presentation logic file. It cannot load presentation data file or output program.


Raw-code

Code of the target program language (such as Ruby, PHP, ...) can be in PL program. '::: raw code' represents a raw-code of target program language. Kwartz outputs a string after ':::' as a raw-code.

The following is an example which include PHP code.

PL Program:

::: <?php foreach($hash as $key => $value) { ?>
:print("key=", key, " value=", value, "\n")
::: <?php } ?>

Output Script:

### PHP
 <?php foreach($hash as $key => $value) { ?>
key=<?php echo $key; ?> value=<?php echo $value; ?>
 <?php } ?>

Command line option '--enable_eruby=true' enables you to embed several language code in presentation logic file. See 'Enable eRuby code in presentation logic' for more detail.


Global and Local Variable

In Kwartz, variables are called Global variables which are setted in main program and passed to output script. And variables are called Local variables which are used only in template.

Assum the following presentation data and presentation logic:

Presentation data (analyze.html) :

<html>
  <body>
    <table>
      <caption id="value:title">Sample</caption>
      <tr id="item_list" bgcolor="#{color}#">
        <td id="value:item_ctr">1</td>
	<td id="value:item">Foo</td>
      </tr>
    </table>
  </body>
</html>

Presentation logic (analyze.plogic) :

:elem(item_list)
  :set(item_ctr = 0)
  :foreach(item = item_list)
    :set(item_ctr += 1)
    :set(color = item_ctr%2 == 0 ? '#FFCCCC' : '#CCCCFF')
    @stag
    @cont
    @etag
  :end
:end

There are several variables. They are classified as bellow:

Global variables
Variables title and item_list are needed to be setted in main program and passed to template. These variables are called Global variables in Kwartz.
Local variables
Variables item, item_ctr and color are used only in template. These variables are called Local variables in Kwartz.

Invoking kwartz command with command option -a analyze analyzes template and reports global/local variables.

$ kwartz -p analyze.plogic -a analyze analyze.html
global variables: title item_list
local variables:  color item item_ctr

Kwartz detemines global/lobal variables according to the following rule:

Kwartz reports warnings if you global variables are appeared in left-side of assignment or used as loop variable of foreach statement. Because role of template system is to display global variables, and templates should not change or modify values of global variables. In addition, kwartz reports warning when uninitalized local variables are used in template.

Analyzing template and reporting global/local variables are very useful, especially presentation data/logic are large and complex. It also helps you to find typo of variable names.


Notes


Features under consideration

The following features are not implemented. They may be implemented in the future release (or not).



Practical Examples

Border colored table

This is a example of border colored table. Each colors in odd lines and even lines are different. The example is so easy that you'll do it only with directives.

Presentation data(table1.html):

<table border="0">
  <tbody id="Foreach:user=user_list">
    <tr bgcolor="#CCCCFF"
        id="attr:bgcolor=color;set:color=user_ctr%2==0?'#FFCCCC':'#CCCCFF'">
      <td id="value:user[:name]">foo</td>
      <td id="value:user[:email]">foo@foo.com</td>
    </tr>
    <tr id="dummy:d1">
      <td>bar</td>
      <td>bar@bar.net</td>
    </tr>
    <tr id="dummy:d2">
      <td>baz</td>
      <td>baz@baz.org</td>
    </tr>
  </tbody>
</table>

Intermediate code:

:print("<table border=\"0\">\n")
:set(user_ctr = 0)
:foreach(user = user_list)
  :set(user_ctr += 1)
  :print("  <tbody>\n")
  :set(color=user_ctr%2==0?'#FFCCCC':'#CCCCFF')
  :print("    <tr bgcolor=\"", color, "\">\n")
  :print("      <td>", user[:name], "</td>\n")
  :print("      <td>", user[:email], "</td>\n")
  :print("    </tr>\n")
  :print("  </tbody>\n")
:end
:print("</table>\n")

Compile:

$ kwartz -l ruby     table1.html > table1.rb
$ kwartz -l ruby2    table1.html > table1.rb2
$ kwartz -l php      table1.html > table1.php
$ kwartz -l jsp      table1.html > table1.jsp
$ kwartz -l eruby    table1.html > table1.rhtml
$ kwartz -l erb      table1.html > table1.erb
$ kwartz -l velocity table1.html > table1.vm

The following output scripts will be created after compiling.

Ruby:

print "<table border=\"0\">\n"
user_ctr = 0
for user in user_list do
  user_ctr += 1
  print "  <tbody>\n"
  color = (user_ctr % 2 == 0 ? "\#FFCCCC" : "\#CCCCFF")
  print "    <tr bgcolor=\"", color, "\">\n"
  print "      <td>", user[:name], "</td>\n"
  print "      <td>", user[:email], "</td>\n"
  print "    </tr>\n"
  print "  </tbody>\n"
end
print "</table>\n"

Ruby2:

_s << "<table border=\"0\">\n"
user_ctr = 0
for user in user_list do
  user_ctr += 1
  _s << "  <tbody>\n"
  color = (user_ctr % 2 == 0 ? "\#FFCCCC" : "\#CCCCFF")
  _s << "    <tr bgcolor=\"" << (color).to_s << "\">\n"
  _s << "      <td>" << (user[:name]).to_s << "</td>\n"
  _s << "      <td>" << (user[:email]).to_s << "</td>\n"
  _s << "    </tr>\n"
  _s << "  </tbody>\n"
end
_s << "</table>\n"

PHP:

<table border="0">
<?php $user_ctr = 0; ?>
<?php foreach ($user_list as $user) { ?>
  <?php $user_ctr += 1; ?>
  <tbody>
  <?php $color = ($user_ctr % 2 == 0 ? '#FFCCCC' : '#CCCCFF'); ?>
    <tr bgcolor="<?php echo $color; ?>">
      <td><?php echo $user['name']; ?></td>
      <td><?php echo $user['email']; ?></td>
    </tr>
  </tbody>
<?php } ?>
</table>

JSP:

<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<table border="0">
<c:set var="user_ctr" value="0"/>
<c:forEach var="user" items="${user_list}">
 <c:set var="user_ctr" value="${user_ctr + 1}"/>
  <tbody>
 <c:choose>
<c:when test="${user_ctr % 2 == 0}">
  <c:set var="color" value="#FFCCCC"/>
 </c:when>
 <c:otherwise>
  <c:set var="color" value="#CCCCFF"/>
 </c:otherwise>
 </c:choose>
    <tr bgcolor="<c:out value="${color}" escapeXml="false"/>">
      <td><c:out value="${user['name']}" escapeXml="false"/></td>
      <td><c:out value="${user['email']}" escapeXml="false"/></td>
    </tr>
  </tbody>
</c:forEach>
</table>

eRuby:

<table border="0">
<% user_ctr = 0
 %><% for user in user_list do
 %><% user_ctr += 1
 %>  <tbody>
<% color = (user_ctr % 2 == 0 ? '#FFCCCC' : '#CCCCFF')
 %>    <tr bgcolor="<%= color %>">
      <td><%= user[:name] %></td>
      <td><%= user[:email] %></td>
    </tr>
  </tbody>
<% end
 %></table>

ERB:

<table border="0">
% user_ctr = 0
% for user in user_list do
%   user_ctr += 1
  <tbody>
%   color = (user_ctr % 2 == 0 ? '#FFCCCC' : '#CCCCFF')
    <tr bgcolor="<%= color %>">
      <td><%= user[:name] %></td>
      <td><%= user[:email] %></td>
    </tr>
  </tbody>
% end
</table>

Velocity:

<table border="0">
#set ($user_ctr = 0)
#foreach ($user in $user_list)
  #set ($user_ctr = $user_ctr + 1)
  <tbody>
  #if ($user_ctr % 2 == 0)
    #set ($color = '#FFCCCC')
  #else
    #set ($color = '#CCCCFF')
  #end
    <tr bgcolor="$!{color}">
      <td>$!{user.name}</td>
      <td>$!{user.email}</td>
    </tr>
  </tbody>
#end
</table>

Navigation of 'Next' or 'Previous'

If there is a sequence of HTML files, each files should have navigation link such as 'Next page' or 'Previous page'. Here we create the next/previous link.

Presentation Data (navilink.html):

<html>
  <body>
    <span id="mark:navilink">
      <a id="mark:prev" href="#{prev_url}#">
        &lt; Previous page
      </a>
      &nbsp;
      <a id="mark:next" href="#{next_url}#">
        Next page &gt;
      </a>
    </span>

    ......
    ......
    ......

    <span id="mark:navilink2">
      &lt; Previous page  &nbsp;  Next page &gt;
    </span>

  </body>
</html>

Presentation Logic (navilink.plogic):

## if URL is null then don't print start-tag and end-tag
:elem(next)
  :if(next_url != null)
    @stag
    @cont
    @etag
  :else
    @cont
  :end
:end
:elem(prev)
  :if(prev_url != null)
    @stag
    @cont
    @etag
  :else
    @cont
  :end
:end

## replace an element 'navi2' with an element 'navi'.
:elem(navilink2)
  @elem_navilink
:end

You can use kd="replace:navilink" to replace an element named 'navilink2' with an element named 'navilink'.

Compile:

$ kwartz -p navilink.plogic -l ruby  navilink.html > navilink.rb
$ kwartz -p navilink.plogic -l ruby2 navilink.html > navilink.rb2
$ kwartz -p navilink.plogic -l php   navilink.html > navilink.php
$ kwartz -p navilink.plogic -l jsp   navilink.html > navilink.jsp
$ kwartz -p navilink.plogic -l eruby navilink.html > navilink.rhtml
$ kwartz -p navilink.plogic -l erb   navilink.html > navilink.erb
$ kwartz -p navilink.plogic -l velocity navilink.html > navilink.vm

The following output scripts will be created after compiling.

Ruby:

print "<html>\n"
print "  <body>\n"
if prev_url != nil then
  print "      <a href=\"", prev_url, "\">\n"
  print "        &lt; Previous page\n"
  print "      </a>\n"
else
  print "        &lt; Previous page\n"
end
print "      &nbsp;\n"
if next_url != nil then
  print "      <a href=\"", next_url, "\">\n"
  print "        Next page &gt;\n"
  print "      </a>\n"
else
  print "        Next page &gt;\n"
end

    ......
    ......
    ......

if prev_url != nil then
  print "      <a href=\"", prev_url, "\">\n"
  print "        &lt; Previous page\n"
  print "      </a>\n"
else
  print "        &lt; Previous page\n"
end
print "      &nbsp;\n"
if next_url != nil then
  print "      <a href=\"", next_url, "\">\n"
  print "        Next page &gt;\n"
  print "      </a>\n"
else
  print "        Next page &gt;\n"
end
print "\n"
print "  </body>\n"
print "</html>\n"

Ruby2:

_s << "<html>\n"
_s << "  <body>\n"
if prev_url != nil then
  _s << "      <a href=\"" << (prev_url).to_s << "\">\n"
  _s << "        &lt; Previous page\n"
  _s << "      </a>\n"
else
  _s << "        &lt; Previous page\n"
end
_s << "      &nbsp;\n"
if next_url != nil then
  _s << "      <a href=\"" << (next_url).to_s << "\">\n"
  _s << "        Next page &gt;\n"
  _s << "      </a>\n"
else
  _s << "        Next page &gt;\n"
end

    ......
    ......
    ......

if prev_url != nil then
  _s << "      <a href=\"" << (prev_url).to_s << "\">\n"
  _s << "        &lt; Previous page\n"
  _s << "      </a>\n"
else
  _s << "        &lt; Previous page\n"
end
_s << "      &nbsp;\n"
if next_url != nil then
  _s << "      <a href=\"" << (next_url).to_s << "\">\n"
  _s << "        Next page &gt;\n"
  _s << "      </a>\n"
else
  _s << "        Next page &gt;\n"
end
_s << "\n"
_s << "  </body>\n"
_s << "</html>\n"

PHP:

<html>
  <body>
<?php if ($prev_url != NULL) { ?>
      <a href="<?php echo $prev_url; ?>">
        &lt; Previous page
      </a>
<?php } else { ?>
        &lt; Previous page
<?php } ?>
      &nbsp;
<?php if ($next_url != NULL) { ?>
      <a href="<?php echo $next_url; ?>">
        Next page &gt;
      </a>
<?php } else { ?>
        Next page &gt;
<?php } ?>

    ......
    ......
    ......

<?php if ($prev_url != NULL) { ?>
      <a href="<?php echo $prev_url; ?>">
        &lt; Previous page
      </a>
<?php } else { ?>
        &lt; Previous page
<?php } ?>
      &nbsp;
<?php if ($next_url != NULL) { ?>
      <a href="<?php echo $next_url; ?>">
        Next page &gt;
      </a>
<?php } else { ?>
        Next page &gt;
<?php } ?>

  </body>
</html>

JSP:

<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<html>
  <body>
<c:choose>
<c:when test="${prev_url != null}">
      <a href="<c:out value="${prev_url}" escapeXml="false"/>">
        &lt; Previous page
      </a>
</c:when>
<c:otherwise>
        &lt; Previous page
</c:otherwise>
</c:choose>
      &nbsp;
<c:choose>
<c:when test="${next_url != null}">
      <a href="<c:out value="${next_url}" escapeXml="false"/>">
        Next page &gt;
      </a>
</c:when>
<c:otherwise>
        Next page &gt;
</c:otherwise>
</c:choose>

    ......
    ......
    ......

<c:choose>
<c:when test="${prev_url != null}">
      <a href="<c:out value="${prev_url}" escapeXml="false"/>">
        &lt; Previous page
      </a>
</c:when>
<c:otherwise>
        &lt; Previous page
</c:otherwise>
</c:choose>
      &nbsp;
<c:choose>
<c:when test="${next_url != null}">
      <a href="<c:out value="${next_url}" escapeXml="false"/>">
        Next page &gt;
      </a>
</c:when>
<c:otherwise>
        Next page &gt;
</c:otherwise>
</c:choose>

  </body>
</html>

eRuby:

<html>
  <body>
<% if prev_url != nil then
 %>      <a href="<%= prev_url %>">
        &lt; Previous page
      </a>
<% else
 %>        &lt; Previous page
<% end
 %>      &nbsp;
<% if next_url != nil then
 %>      <a href="<%= next_url %>">
        Next page &gt;
      </a>
<% else
 %>        Next page &gt;
<% end
 %>
    ......
    ......
    ......

<% if prev_url != nil then
 %>      <a href="<%= prev_url %>">
        &lt; Previous page
      </a>
<% else
 %>        &lt; Previous page
<% end
 %>      &nbsp;
<% if next_url != nil then
 %>      <a href="<%= next_url %>">
        Next page &gt;
      </a>
<% else
 %>        Next page &gt;
<% end
 %>
  </body>
</html>

ERB:

<html>
  <body>
% if prev_url != nil then
      <a href="<%= prev_url %>">
        &lt; Previous page
      </a>
% else
        &lt; Previous page
% end
      &nbsp;
% if next_url != nil then
      <a href="<%= next_url %>">
        Next page &gt;
      </a>
% else
        Next page &gt;
% end

    ......
    ......
    ......

% if prev_url != nil then
      <a href="<%= prev_url %>">
        &lt; Previous page
      </a>
% else
        &lt; Previous page
% end
      &nbsp;
% if next_url != nil then
      <a href="<%= next_url %>">
        Next page &gt;
      </a>
% else
        Next page &gt;
% end

  </body>
</html>

Velocity:

<html>
  <body>
#if ($prev_url)
      <a href="$!{prev_url}">
        &lt; Previous page
      </a>
#else
        &lt; Previous page
#end
      &nbsp;
#if ($next_url)
      <a href="$!{next_url}">
        Next page &gt;
      </a>
#else
        Next page &gt;
#end

    ......
    ......
    ......

#if ($prev_url)
      <a href="$!{prev_url}">
        &lt; Previous page
      </a>
#else
        &lt; Previous page
#end
      &nbsp;
#if ($next_url)
      <a href="$!{next_url}">
        Next page &gt;
      </a>
#else
        Next page &gt;
#end

  </body>
</html>

Breadclumbs

It is very popular that Web page have links such as 'Home > Ruby > Kwartz'. It is called 'Breadcrumbs' or 'Trail'.

Here we create that.

## Ruby
breadcrumbs = []
breadcrumbs << { :title => 'Home',   :path => '/' }
breadcrumbs << { :title => 'Ruby',   :path => '/ruby/' }
breadcrumbs << { :title => 'Kwartz', :path => '/ruby/kwartz/' }

## PHP
$breadcrumbs = array('title' => 'Home',   'path' => '/');
$breadcrumbs = array('title' => 'Ruby',   'path' => '/ruby/');
$breadcrumbs = array('title' => 'Kwartz', 'path' => '/ruby/kwartz/');

## Java
List breadcrumbs = new ArrayList();
Map  hash = new HashMap();
hash.put('title', 'Home');
hash.put('path',  '/');
breadcrumbs.add(hash);
hash = new HashMap();
hash.put('title', 'Ruby')
hash.put('path', '/ruby/')
breadcrumbs.add(hash);
hash = new HashMap();
hash.put('title', 'Kwartz')
hash.put('path', '/ruby/kwartz/')
breadcrumbs.add(hash);

Presentation Data:

<span id="mark:breadcrumbs">
  <a id="mark:item" href="#{item_path}#">
    <span id="value:item_title">Home</span>
  </a>
  <span id="mark:arrow"> &gt; </span>
</span>

Presentation Logic:

:elem(breadcrumbs)
  :set(item_ctr = 0)
  :foreach(item = breadcrumbs)
    :set(item_ctr += 1)
    :if(item_ctr > 1)       ## each time  except first time
      @elem_arrow           ## print &lt;
    :end
    @elem_item              ## and print <a></a>.
  :end
:end

:elem(item)
  :set(item_path  = item[:path])   ## retrieve path and
  :set(item_title = item[:title])  ## title from a hash.
  :if(item_path!=null)
    @stag
    @cont
    @etag
  :else                     ## if path is null then
    @cont                   ## don't print <a></a>.
  :end
:end

Compile:

$ kwartz -p breadcrumbs.plogic -l ruby  breadcrumbs.html > breadcrumbs.rb
$ kwartz -p breadcrumbs.plogic -l ruby2 breadcrumbs.html > breadcrumbs.rb2
$ kwartz -p breadcrumbs.plogic -l php   breadcrumbs.html > breadcrumbs.php
$ kwartz -p breadcrumbs.plogic -l jsp   breadcrumbs.html > breadcrumbs.jsp
$ kwartz -p breadcrumbs.plogic -l eruby breadcrumbs.html > breadcrumbs.rhtml
$ kwartz -p breadcrumbs.plogic -l erb   breadcrumbs.html > breadcrumbs.erb
$ kwartz -p breadcrumbs.plogic -l velocity breadcrumbs.html > breadcrumbs.vm

The following output scripts will be created after compiling.

Ruby:

item_ctr = 0
for item in breadcrumbs do
  item_ctr += 1
  if item_ctr > 1 then
    print "&gt; "
  end
  item_path = item[:path]
  item_title = item[:title]
  if item_path != nil then
    print "  <a href=\"", item_path, "\">\n"
    print item_title
    print "  </a>\n"
  else
    print item_title
  end
end

Ruby2:

item_ctr = 0
for item in breadcrumbs do
  item_ctr += 1
  if item_ctr > 1 then
    _s << "&gt; "
  end
  item_path = item[:path]
  item_title = item[:title]
  if item_path != nil then
    _s << "  <a href=\"" << (item_path).to_s << "\">\n"
    _s << (item_title).to_s
    _s << "  </a>\n"
  else
    _s << (item_title).to_s
  end
end

PHP:

<?php $item_ctr = 0; ?>
<?php foreach ($breadcrumbs as $item) { ?>
  <?php $item_ctr += 1; ?>
  <?php if ($item_ctr > 1) { ?>
&gt; <?php } ?>
  <?php $item_path = $item['path']; ?>
  <?php $item_title = $item['title']; ?>
  <?php if ($item_path != NULL) { ?>
  <a href="<?php echo $item_path; ?>">
<?php echo $item_title; ?>  </a>
  <?php } else { ?>
<?php echo $item_title; ?><?php } ?>
<?php } ?>

JSP:

<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<c:set var="item_ctr" value="0"/>
<c:forEach var="item" items="${breadcrumbs}">
 <c:set var="item_ctr" value="${item_ctr + 1}"/>
 <c:choose>
<c:when test="${item_ctr > 1}">
&gt; </c:when>
 </c:choose>
 <c:set var="item_path" value="${item['path']}"/>
 <c:set var="item_title" value="${item['title']}"/>
 <c:choose>
<c:when test="${item_path != null}">
  <a href="<c:out value="${item_path}" escapeXml="false"/>">
<c:out value="${item_title}" escapeXml="false"/>  </a>
 </c:when>
 <c:otherwise>
<c:out value="${item_title}" escapeXml="false"/></c:otherwise>
 </c:choose>
</c:forEach>

eRuby:

<% item_ctr = 0
 %><% for item in breadcrumbs do
 %><% item_ctr += 1
 %><% if item_ctr > 1 then
 %>&gt; <% end
 %><% item_path = item[:path]
 %><% item_title = item[:title]
 %><% if item_path != nil then
 %>  <a href="<%= item_path %>">
<%= item_title %>  </a>
<% else
 %><%= item_title %><% end
 %><% end
 %>

ERB:

% item_ctr = 0
% for item in breadcrumbs do
%   item_ctr += 1
%   if item_ctr > 1 then
&gt; 
%   end
%   item_path = item[:path]
%   item_title = item[:title]
%   if item_path != nil then
  <a href="<%= item_path %>">
<%= item_title %>  </a>
%   else
<%= item_title %>
%   end
% end

Velocity:

#set ($item_ctr = 0)
#foreach ($item in $breadcrumbs)
  #set ($item_ctr = $item_ctr + 1)
  #if ($item_ctr > 1)
&gt; #end
  #set ($item_path = $item.path)
  #set ($item_title = $item.title)
  #if ($item_path)
  <a href="$!{item_path}">
$!{item_title}  </a>
  #else
$!{item_title}#end
#end

This example shows you how to switch messages according to condition.

Presentaion data:

  <span id="noerror">No errors.</span>
  <font id="error" color="red">Error occurred!</font>

Presentaion logic:

:elem(error_report)
  @stag
  :if(error_report == null)
     @elem_noerror	## prints 'No errors.'
  :else
     @elem_error	## prints 'Error occurred!'
  :end
  @etag
:end

In the above presentation logic, elements(@elem_noerror and @elem_noerror) are used instead of content of error_report element. This way is very useful. Remember it.

If you have an array which contains several error messages, say:

Presentaion data:

<font id="error_list" color="red">
  <span id="value:error">Name is required.</span><br>
</font>

Presentation logic:

:elem(error_list)
  :if(error_list != null)
    @stag
    :foreach(error = error_list)
      @cont
    :end
    @cont
  :end
:end

From the viewpoint of 'Separation of presentation from business logic', it is not a good idea to set error message in main program, because error messages should be included in presentation layer. Role of presentation layer is to determine what message should be used according to error code.

The following way is one of the idea to share the responsibility of template and main program.

Presentaion Data:

<font id="if:errors!=null" color="red">
  <!-- Display error messages that is prepared in main program. -->
  <span id="if:errors['age']!=null">#{errors['age']}#<br><span>
  <span id="if:errors['tel']!=null">#{errors['tel']}#<br><span>
  <!-- Display original error messages. -->
  <span id="if:errors['name']!=null">Name is required.<br></span>
  <span id="if:errors['mail']!=null">Mail address is required.<br></span>
</font>

You may create a error message catalog and load it from main program. It is also one of the preferred approach.


HTML Form

An example in this section is a form to register user name and gender.

There are several files in this example.

register.cgi
CGI Main program (Ruby).
register.html
Template for registration page.
register.rhtml
Output script for registration page (eRuby).
finish.html
Template for finished page.
finish.rhtml
Output script for finished page (eRuby).

Form CGI program (main program) is created with the following approach:

Auto-sanitizing and eruby is adopted in this example.

Template for registration page(register.html):

<html>
 <body>
  <form action="/cgi-bin/register.cgi" method="POST">

   <span id="if:error_list==null">
    <font color="#FF0000" id="foreach:error=error_list">
     <span id="value:error">Name is empty.</span><br>
    </font>
   </span>

   <table border="0" cellspacing="1" cellpadding="5">

    <tr>
     <td>Name:</td>
     <td>
      <input type="text" name="name" size="20"
             id="attr:value=param[:name]">
     </td>
    </tr>

    <tr>
     <td>Gender:</td>
     <td>
      <input type="radio" name="gender" value="M"
             #{X(param[:gender]=='M'?'checked':'')}#>Man
      &nbsp;
      <input type="radio" name="gender" value="W"
             #{X(param[:gender]=='W'?'checked':'')}#>Woman
     </td>
    </tr>

    <tr>
     <td colspan="2" align="right">
      <input type="submit" value=" Regist ">
      <input type="reset"  value="reset">
     </td>
    </tr>

   </table>
  </form>
 </body>
</html>

Output script for registration page(register.rhtml):

<html>
 <body>
  <form action="/cgi-bin/register.cgi" method="POST">

<% if error_list == nil then
 %><% for error in error_list do
 %>    <font color="#FF0000">
<%= CGI.escapeHTML((error).to_s) %><br>
    </font>
<% end
 %><% end
 %>
   <table border="0" cellspacing="1" cellpadding="5">

    <tr>
     <td>Name:</td>
     <td>
      <input type="text" name="name" size="20" value="<%= CGI.escapeHTML((param[:name]).to_s) %>">
     </td>
    </tr>

    <tr>
     <td>Gender:</td>
     <td>
      <input type="radio" name="gender" value="M"
             <%= (param[:gender] == 'M' ? 'checked' : '') %>>Man
      &nbsp;
      <input type="radio" name="gender" value="W"
             <%= (param[:gender] == 'W' ? 'checked' : '') %>>Woman
     </td>
    </tr>

    <tr>
     <td colspan="2" align="right">
      <input type="submit" value=" Regist ">
      <input type="reset"  value="reset">
     </td>
    </tr>

   </table>
  </form>
 </body>
</html>

Template of a finished page(finish.html):

<html>
 <body>
  Registration finished with the following data:<br>
  Name:
   <span id="value:param[:name]">Foo</span><br>
  Gender:
   <span id="if:param[:gender]=='M'">Man</span>
   <span id="if:param[:gender]=='W'">Woman</span>
 </body>
</html>

Output script for finished page(finish.rhtml):

<html>
 <body>
  Registration finished with the following data:<br>
  Name:
<%= CGI.escapeHTML((param[:name]).to_s) %><br>
  Gender:
<% if param[:gender] == 'M' then
 %>Man<% end
 %><% if param[:gender] == 'W' then
 %>Woman<% end
 %> </body>
</html>

CGI main program(register.cgi):

#!/usr/bin/ruby

## create a hash object from CGI object
require 'cgi'
cgi = CGI.new
param = {}
cgi.param.each do |key, value|
  param[key.intern] = value[0]
end
param.default = ''

## action for submit button
error_list = nil
if !param.empty? then
  ## check input data
  error_list = []
  if param[:name] == '' then
    error_list << 'Name is empty.'
  end
  case param[:gender]
  when 'M', 'W'
    # OK
  else
    error_list << 'Gender is not selected.'
  end

  ## if input parameter is valid then print finished page(finish.rhtml),
  ## else print the sampe page(register.rhtml)
  if error_list.empty? then
    error_list = nil
    filename = 'finish.rhtml'
    ... data registration process ...
  else
    filename = 'register.rhtml'
  end

end

## print web page
require 'eruby'
ERuby::import(filename)

Calendar

This is an example to show calendar, and also an example which explains component-approach development. Here is the final output.

Calendar requires a complex presentation logic. Therefore, this is one of the best example which represents effectiveness of 'separation of presentation logic and presentation data'.

This example has two presentation data files and two presentation logic files. And main program is writtein in PHP.

calendar.html, calendar.plogic
Presentation data file and presentation logic file to display calendar of a month.
calendar-page.html, calendar-page.plogic
Presentation data file and presentation logic file for whole web page.
calendar-page.php
Main program.

Presentation Data (calendar.html) :

     <table cellpadding="2" summary="">
       <caption>
	 <i id="value:month">Jan</i>&nbsp;<i id="value:year">20XX</i>
       </caption>
       <thead>
	 <tr bgcolor="#CCCCCC">
	   <th><span class="holiday">S</span></th>
	   <th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th>
	 </tr>
       </thead>
       <tbody>
	 <tr id="mark:week">
	   <td><span id="mark:day" class="holiday">&nbsp;</span></td>
	   <td id="dummy:d1">&nbsp;</td>
	   <td id="dummy:d2">1</td>
	   <td id="dummy:d3">2</td>
	   <td id="dummy:d4">3</td>
	   <td id="dummy:d5">4</td>
	   <td id="dummy:d6">5</td>
	 </tr>
	 <tr id="dummy:w1">
	   <td><span class="holiday">6</span></td>
	   <td>7</td><td>8</td><td>9</td>
	   <td>10</td><td>11</td><td>12</td>
	 </tr>
	 <tr id="dummy:w2">
	   <td><span class="holiday">13</span></td>
	   <td>14</td><td>15</td><td>16</td>
	   <td>17</td><td>18</td><td>19</td>
	 </tr>
	 <tr id="dummy:w3">
	   <td><span class="holiday">20</span></td>
	   <td>21</td><td>22</td><td>23</td>
	   <td>24</td><td>25</td><td>26</td>
	 </tr>
	 <tr id="dummy:w4">
	   <td><span class="holiday">27</span></td>
	   <td>28</td><td>29</td><td>30</td>
	   <td>31</td><td>&nbsp;</td><td>&nbsp;</td>
	 </tr>
       </tbody>
     </table>
     &nbsp;

Presentation logic (calendar.plogic) :

:elem(week)

  :set(day = '&nbsp')
  :set(wday = 1)
  :while(wday < first_weekday)
    :if(wday == 1)
      @stag
    :end
    @cont
    :set(wday += 1)
  :end

  :set(day = 0)
  :set(wday -= 1)
  :while(day < num_days)
    :set(day += 1)
    :set(wday = wday % 7 + 1)
    :if(wday == 1)
      @stag
    :end
    @cont
    :if(wday == 7)
      @etag
    :end
  :end

  :if(wday != 7)
    :set(day = '&nbsp;')
    :while(wday != 6)
      @cont
      :set(wday += 1)
    :end
    @etag
  :end

:end

:elem(day)
  :if(wday == 1)
    @stag
    :print(day)
    @etag
  :else
    :print(day)
  :end
:end

Presentation data (calendar-page.html) :

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <style type="text/css">
      <!--
	.holiday   {color:#FF0000;}
	-->
    </style>
  </head>
  <body>
    
    <table border="0" summary="">
      <tr id="mark:calendar_list">
	<td id="mark:calendar" valign="top">
	  .... calendar here ...
	</td>
      </tr>
    </table>
    
  </body>
</html>

Presentation logic (calendar-page.plogic) :

:elem(calendar_list)
  :set(calendar_ctr = 0)
  :foreach(calendar = calendar_list)
    :set(calendar_ctr += 1)
    :if(calendar_ctr % colnum == 1)
      @stag
    :end
    @cont
    :if(calendar_ctr % colnum == 0)
      @etag
    :end
  :end
  :if(calendar_ctr % colnum != 0)
    :set(calendar = '')
    :while(calendar_ctr % colnum != 0)
      @cont
      :set(calendar_ctr += 1)
    :end
    @etag
  :end
:end

:elem(calendar)
   @stag
   :print(calendar)
   @etag
:end

Main program (calendar-main.php) :

<?php
	// year, month, number of days, 1st weekday
	// (or use date() function)
	$month_data[] = array(2004, 'Jan', 31, 'Thu');
	$month_data[] = array(2004, 'Feb', 29, 'Sat');
	$month_data[] = array(2004, 'Mar', 31, 'Tue');
	$month_data[] = array(2004, 'Apr', 30, 'Thu');
	$month_data[] = array(2004, 'May', 31, 'Sat');
	$month_data[] = array(2004, 'Jun', 30, 'Tue');
	#$month_data[] = array(2004, 'Jul', 31, 'Thu');
	#$month_data[] = array(2004, 'Aug', 31, 'Sun');
	#$month_data[] = array(2004, 'Sep', 30, 'Wed');
	#$month_data[] = array(2004, 'Oct', 31, 'Fri');
	#$month_data[] = array(2004, 'Nov', 30, 'Mon');
	#$month_data[] = array(2004, 'Dec', 31, 'Wed');

	$weekday2num = array( 'Sun'=>1, 'Mon'=>2, 'Tue'=>3, 'Wed'=>4,
			      'Thu'=>5, 'Fri'=>6, 'Sat'=>7,);


	// output buffering start
	ob_start();

	// main loop
	$colnum = 4;
	foreach($month_data as $data) {
		$year	       = $data[0];
		$month         = $data[1];
		$num_days      = $data[2];
		$first_weekday = $weekday2num[$data[3]];

		// include 'calendar.inc' content as string
		include('calendar.php');
		$str = ob_get_contents();
		ob_clean();

		// append content string into $calendar_list[]
		$calendar_list[]  = $str;
	}

	// output buffering stop
	ob_end_clean();

	// include main page, with $calendar_list[]
	include('calendar-page.php');
 ?>

Compile and Execution :

$ kwartz -l php -p calendar.plogic calendar.html > calendar.php
$ kwartz -l php -p calendar-page.plogic calendar-page.html > calendar-page.php
$ php -q calendar-main.php > calendar-main.html


Tips

Get output as string

It is possible to get result of executing output scrit as string in Ruby or PHP.

Use ruby2 or ERB in Ruby:

## ruby2
s = File.open('file.erb') { |f| f.read() }   # or File.read('file.erb') in 1.8
s.untaint
_s = ''
eval s
str = _s			  # get output as string

## ERB
s = File.open('file.erb') { |f| f.read() }   # or File.read('file.erb') in 1.8
require 'erb'
s.untaint
erb = ERB.new(s, $SAFE, '%')
str = erb.result(binding())       # get output as string

Use php2 or Output Buffering functions (ob_start(), ob_get_contents(), ob_end_clean()) in PHP:

// php2
<?php
	include('file.php');
	$str = $_s;
?>

// use output buffering functions
<?php
	ob_start();                 // start output buffering
	include('file.php');
	$str = ob_get_contents();   // get result as string
	ob_end_clean();             // stop output buffering
?>

Auto-compile with comaring timestamp

Auto-compile is available. Auto-compile is a function to compare each file's timestamp and compile it if needed. Compilation will be done when:

Sorry, kwartz is implemented only in Ruby, so auto-compile function is available only for Ruby programmer.

You can use auto-compile with Kwartz::compile(). Here is a sample of main program:

pdata  = 'sample.html'		# presentation data file
script = 'sample.rhtml'		# output script file
plogic = 'sample.plogic'	# presentation logic file
lang   = 'eruby'		# target language

require 'kwartz'
Kwartz::compile(pdata, script, plogic, lang)

requre 'eruby'
ERuby::import(script)

checked, selected, disabled

A function to output 'checked="checked"', 'selected="selected"' or 'disabled="disabled"' easily for HTML/XHTML is added in Kwartz.

#{@CHECK(condition)}# or #{@C(condition)}#

Prints 'checked="checked"' if condition is true

#{@SELECT(condition)}# or #{@S(condition)}#

Prints 'selected="selected"' if condition is true

#{@DISABLE(condition)}# or #{@D(condition)}#

Prints 'disabled="disabled"' if condition is true

For example, see the following presentation data:

<input type="radio" name="gender" value="M"
       #{gender=='M' ? 'checked="checked"' : ''}#>Man
<option name="lang" value="ruby"
       #{lang=='ruby' ? 'selected="selected"' : ''}#>Ruby
<input type="radio" name="os" value="win"
       #{os=='mac' ? 'disabled="disabled"' : ''}#>Windows

You can write the above presentation data more simply like this:

<input type="radio" name="gender" value="M"
       #{@C(gender=='M')}#>Man
<option name="lang" value="ruby"
       #{@S(lang=='ruby')}#>Ruby
<input type="radio" name="os" value="win"
       #{@D(os=='mac')}#>Windows

Kwartz will convert it into the following intermediate code:

:print("<input type=\"radio\" name=\"gender\" value=\"M\"\n")
:print("       ", @C(gender=='M'), ">Man\n")
:print("<option name=\"lang\" value=\"ruby\"\n")
:print("       ", @S(lang=='ruby'), ">Ruby\n")
:print("<input type=\"radio\" name=\"os\" value=\"win\"\n")
:print("       ", @D(os=='mac'), ">Windows\n")

Note: The function is experimental. It may be changed or deleted in the future.


Enable eRuby code in presentation logic

Command line option --enable_eruby=true enables eRuby code appeared in presentation logic. '%' notation is available and you can refer target language name by variable '__lang__' in eRuby code.

Presentation logic:

:set(message = 'a sample message')
:set(number  = 20)
% if __lang__ == 'php'
::: <?php $str = sprintf('(%03d) %s', $number, $message); ?>
% elsif __lang__ == 'ruby'
::: s = '(%03d) %s' % [number, message]
% elsif __lang__ == 'erb'
:::% str = '(%03d) %s' % [number, message]
% elsif __lang__ == 'eruby'
::: <<% %>% str = '(%03d) %s' % [number, message] %<% %>>
% else
:set(s = '(' .+ number .+ ') ' .+ message)
% end
:print(s, "\n")

Output script:

### Ruby
message = "a sample message"
number = 20
 s = '(%03d) %s' % [number, message]
print s, "\n"

### PHP
<?php $message = 'a sample message'; ?>
<?php $number = 20; ?>
 <?php $str = sprintf('(%03d) %s', $number, $message); ?>
<?php echo $s; ?>

### JSP + JSTL
<c:set var="message" value="a sample message"/>
<c:set var="number" value="20"/>
<c:set var="s" value="${'('}${number}${') '}${message}"/>
<c:out value="${s}" escapeXml="false"/>

### eRuby
<% message = 'a sample message'
 %><% number = 20
 %> <% str = '(%03d) %s' % [number, message] %>
<%= s %>

### ERB
% message = 'a sample message'
% number = 20
% str = '(%03d) %s' % [number, message]
<%= s %>

### Velocity
#set ($message = 'a sample message')
#set ($number = 20)
#set ($s = "(${number}) ${message}")
$!{s}

eRuby code is executed with ERB. If you are using Ruby 1.8.X or later, you don't need to install ERB because it is bundled with Ruby 1.8.X. If you are using Ruby 1.6.X, you have to install ERB.


Environment variable KWARTZ_OPTIONS

You can specify kwartz command line options at an environment variable 'KWARTZ_OPTIONS'.

For example, if you are using ERB as a default target language and auto-sanitizing, set the environment variable like this:

$ export KWARTZ_OPTIONS='-l erb -s'    # sh, bash
$ setenv KWARTZ_OPTIONS '-l erb -s'    # csh, tcsh

Value of the environment variable is overwrited by actual command-line options. For example, when you have done the above setting and specified a command-line option '-l eruby', kwartz will output a script for eRuby, not ERB.

Note: kwartz command parses a value of the environment variable by String#split(' '). Therefore, kwartz command cannot parse a complex variable of the enviroment variable correctly.


Compile template as method of Ruby/PHP

Using 'mkmethod' script, you can compile template and define it as method or module of Ruby.

Usage of mkmethod is here:

bash$ mkmethod -h
Usage: mkmethod [-svh] [-p file] [-l lang] [-M module] [-m method] file.html
  -p file            : presentation logic file
  -l lang            : ruby/ruby2/eruby/erb/php/php2 (default 'ruby2')
  -M module/class    : module/class name (default none)
  -m method          : method name (default 'expand_' + file)
  -A arg1,arg2,...   : method arguments (default nil)
  -s                 : sanitizing (equals to '--escape=true')
  -h, --help         : print help and exit
  -v                 : print version and exit
  --optname=value    : options for kwartz

Command line option '-l ruby', '-l eruby' or '-l php' creates a method which prints result to standard output, '-l ruby2', '-l erb' or '-l php2' creates a method which returns output as a string. Default is 'ruby2'.

bash$ mkmethod -p hoge.plogic hoge.html
  def expand_hoge(_args)
    user = _args[:user]
    list = _args[:list]
    _s = ''
    _s << "Hello " << (user).to_s << "!\n"
    _s << "<ul>\n"
    for item in list do
      _s << "  <li>" << (item).to_s << "</li>\n"
    end
    _s << "</ul>\n"
    return _s
  end

bash$ mkmethod -l php2 -p hoge.plogic hoge.html
<?php
        function expand_hoge(&$_args) {
                $user = &$_args['user'];
                $list = &$_args['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;
        } // function end
?>

Command line option '-M' enables you to specify module name in Ruby or class name in PHP.

bash$ mkmethod -p hoge.plogic -M Hoge hoge.html
module Hoge
  def self.expand_hoge(_args)
    user = _args[:user]
    list = _args[:list]
    _s = ''
    _s << "Hello " << (user).to_s << "!\n"
    _s << "<ul>\n"
    for item in list do
      _s << "  <li>" << (item).to_s << "</li>\n"
    end
    _s << "</ul>\n"
    return _s
  end
end

bash$ mkmethod -l php2 -p hoge.plogic -M Hoge hoge.html
<?php
class Hoge {
        function expand_hoge(&$_args) {
                $user = &$_args['user'];
                $list = &$_args['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;
        } // function end
} // class end
?>

Script 'mkmethod' detects global variables of template automatically using Analyze function of Kwartz. You can specify method arguments with command line option '-A'.

bash$ mkmethod -p hoge.plogic -M Hoge -A 'user,list' hoge.html
module Hoge
  def self.expand_hoge(_args)
    user = _args[:user]
    list = _args[:list]
    return self._expand_hoge(user, list)
  end
  def self._expand_hoge(user, list)
    _s = ''
    _s << "Hello " << (user).to_s << "!\n"
    _s << "<ul>\n"
    for item in list do
      _s << "  <li>" << (item).to_s << "</li>\n"
    end
    _s << "</ul>\n"
    return _s
  end
end

bash$ mkmethod -l php2 -p hoge.plogic -M Hoge -A 'user,list' hoge.html
<?php
class Hoge {
        function expand_hoge(&$_args) {
                $user = &$_args['user'];
                $list = &$_args['list'];
                return Hoge::_expand_hoge($user, $list);
        } // function end
        function _expand_hoge(&$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;
        } // function end
} // class end
?>

Command line option for sanitizing '-s' or '--escape=true' are also avairable.


Use W3C Markup Validation Service

W3C provides Markup Validation service (http://validator.w3.org). You will get errors when you tried it with Kwartz HTML template (presentation data file) because of 'kd' attribute.

There are nice PHP/CGI scripts (validator.php and validator.cgi) in Kwartz archive. They delete 'kd' attribtes from a HTML file and pass it to W3C Markup Validation Service. Put them at your web server and try it. Or you can try it at Kwartz website.


Avoid same variable name as keywords

If you are using Ruby or JSP, that is, languages which doesn't require '$' or other prefix for variable, avoid same variable name as keywords of the language. And also avoid the same name as built-in variables or build-in functions.

If you use a same name as keywords or build-in variables, you'll get strange errors.

For example, the following are keywords in Ruby.

Keywords in Ruby
    BEGIN    class    ensure   nil      self     when
    END      def      false    not      super    while
    alias    defined? for      or       then     yield
    and      do       if       redo     true
    begin    else     in       rescue   undef
    break    elsif    module   retry    unless
    case     end      next     return   until

JSP(and JSTL's Expression Lanugage) have the following built-in variables or keywords (see JavaServer Pages(TM) Standard Tag Library Specification (Final Release) for detail).

keywords and built-in variables in JSP and JSTL Expression Language
    and		or	not
    eq		ne	lt	le	gt	ge
    div		mod
    true	false		null
    empty
    page	pageScope	request		requestScope
    session	sessionScope	application	applicationScope
    header	headerValues	param		paramValues
    cookie

PHP user doesn't need to wonder such problem because PHP needs to use variable prefix '$', but if you may change programming language from PHP to Java or other, you should remind this problem.


Use name 'param' as a variable for HTTP request parameters

URL Parameter variable is named 'param' in JSTL's Expression Language. You should also use name 'param' for parameters in Ruby or PHP for portability of presentation layer.

For example, the following HTML page exists:

<form action="/cgi/form.cgi" method="post">
  User name: <input type="text" name="user"><br>
  Age:       <input type="text" name="age"><br>
  <input type="submit">
</form>

You should create the following presentation data.

Confirmation:
 User name:<span id="value:param['user']">Foobar</span><br>
 Age:      <span id="value:param['age']">99</span><br>

If you need portability of presentation data and logic, you should use name 'param' as form parameters variable in all languages.

For example, in Ruby:

require 'cgi'
cgi = CGI.new
param = {}
cgi.params.each do |key,value|
  param[key] = value.first
end
....
s = File.open('form.rb') { |f| f.read }
s.untaint
eval s
## or ERuby::import('form.rhtml'), etc..

For example, in PHP:

<?php
     $param = &$_REQUEST;
     ....
     include('form.php');
 ?>

By the same reason, you should use 'cookie' as cookie variable, and use 'session' as session variable.

However, JSP doesn't allow us to change request values of parameters (*9). For example, you can write a code such as $_POST['user'] = trim($_POST['user']); in PHP, but you cannot in JSP. If you want avoid this restriction, you should set request parameters in a HashMap object and name it other name but 'param'.

// Servlet Example
public void doPost(HttpServletRequest request, HttpServletResponse response)
       throws ServletException, IOException {
   
   // Get HTTP request parameters and set them into HashMap object.
   String[] names = { 'name', 'age' };
   for (int i = 0; i < names.length; i++) {
      String key   = names[i];
      String value = (String)request.getParameter(key);
      if (value != null) {
         value = value.trim();            // trim an extra space
         params.put(key, value); 
      }
   }
   
   // Regist HashMap object with a name 'params'.
   // Use 'params' instead of 'param' in JSP and JSTL.
   request.setAttribute("params", params);
   
   // Forward to JSP
   String filename = "form.jsp";
   String url = filename;
   request.getRequestDispatcher(url).forward(request, response);
}
(*9)
It is because that there is getParameter() method in HttpServletRequest but not setParameter() method.

Allow only logical expression as conditional expresion

It is very different in each programming language how to interpret conditional expression of if-statement or conditional operator. Therefore, you should allow only logical expression in conditional expression.

For example, see the following presentation data:

<font id="if:error" color="red">
  ERROR! : #{error}#
</font>

In this case, programming languages takes each own ointerpretation of value of error as conditional expression.

Results of interpretation of each programming languages
value of error Ruby PHP JSP(JSTL) Velocity
empty string ('') True False False True
string (not empty) True True False True
zero True False False True
number (not zero) True True False True
true True True True True
false False False False False
null False False False False

If you want to make templates portable, you should describe only logical expressin in conditional expression. For example, ':if(error)' should be ':if(error!=null)' or ':if(error!='')', and ':if(!error)' should be ':if(error==null)' or ':if(error=='')'.

If you want to check if string is null or empty, use keyword 'empty'. See empty for detail about keyword 'empty'.



Appendix

Appendix1: kwartz command

Script 'kwartz' is a commad-line script to convert, translate and compile a HTML template into outptu script.

You remember these terms? OK, I'll show you again.

Convert
Transform presentation data into intermediate code.
Translate
Merge intermediate code and presentation logic, and transform them into output script.
Compile
Transform presentation data and presentation logic into output script. 'Compile' means 'convert and traslate'.

And here is the usage of 'kwartz' script.

Usage:

kwartz [options...] [-p plogic-file] file.html > file.output

Process one file (normal mode).

kwartz -O outfile-suffix [-P plogic-suffix] [options...] *.html

Process each files (batch mode). You must specify suffix of output script file with option -O. And you may specify suffix of presentation logic file with option -P.

Options:

-h, --help
Help.
-v
Version information.
-a action
Action to do. action may be 'convert', 'translate', 'compile'(default) or 'analyze'.
-l lang
Target language of output script. lang may be ruby, ruby2, php, php2, jsp, eruby, erb, erbscan, velocity.
-s
Make auto-sanitizing enabled. All language but velocity can be sanitized. This option is equal to --escape=true.
-p plogic-file
Filename of presentation logic. It is possible to specify several filename using ',' as a separator.
-O outfile-suffix
Suffix of output file. Kwartz will be 'batch mode' when option -O is specified.
-P plogic-suffix
Suffix of presentation logic file. Used with batch-mode.
-T
Compare timestamp. If output script file is newer than input, kwartz will do nothing. Used with batch-mode.
-S
Suppress messages. Used with batch-mode.
--attr_name=name
Attribute name used as a directive. Default is 'kd'.
--charset=charset
Character set. kwartz will print '<%@ page contentType="text/html; charset=charset" %>' in JSP.
--delete_idattr=true|false
Delete id="name" from presentation data.
--enable_eruby=true|false
Use eRuby as a preprocessor for presentation logic. '%' notation is available. Variable '__lang__' represents target language name. It needs ERB to be installed.
--escape=true|false
Auto-sanitizing.
--even_value=value
Even value. Default is 'even'. Directive FOREACH and LIST will use this value.
--footer=string
Footer string.
--header=string
Header string. '<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>' is used as default in JSP. If you don't want to print any header text, use --header=''.
--include_path=dir1,dir2],...
Specify directories from which 'include' directive includes.
--load_path=dir1,dir2],...
Specify directories from which 'load' directive or :load() statement loads.
--odd_value=value
Odd value. Default is 'odd'. Directive FOREACH and LIST will use this value.

Example:


appendix2: BNF of PL(Presentation Language)

(undocumented)