Dynamator Pure HTML for every page generation technology.
           

The 20 Minute Guide

Contents:

Hello, World!

We'll start with a Hello World example.

HelloWorld.html
<html>
<head>
<title>Hello World</title>
</head>
<body>
<p id="HelloText">Hello world
</body>
</html>
HelloWorld.dyn
<dynamator language="jsp">
  <prolog>
    <%@ page session="false" %>
    <%!
        private String getGreeting()
        {
            return "Hi!";
        }
    %>
  </prolog>
  <id name="HelloText">
    <content>getGreeting()</content>
  </id>
</dynamator>

The command

java dynamate HelloWorld.html

produces:

 
HelloWorld.jsp
<%-- generated by Dynamator Sun Jun 24 17:01:47 CDT 2001
--%>
    <%@ page session="false" %>
    <%!
        private String getGreeting()
        {
            return "Hi!";
        }
    %>
                           <html>
  <head>
    <title>Hello World</title>
  </head>
  <body>
  <p id="HelloText"><%= getGreeting() %></p>
  </body>
</html>

Here's what happened:

  1. Dynamator generated a JSP file because HelloWorld.dyn specifies language="jsp".
  2. Because the template is an HTML file, Dynamator ran it through JTidy to convert it into XML. Tidy added the </p>. Tidy also changed the formatting a bit without affecting the appearance of the page in a browser.
  3. Dynamator added the "generated by Dynamator" signature so maintainers would know immediately that the JSP file is generated, not hand-coded. (The signature is optional.)
  4. Dynamator placed the contents of the prolog element at the beginning of the generated JSP file.
  5. Dynamator found an HTML element with an id of "HelloText", so it replaced that element's content with the program expression in the Dynamator element.

Now that you've had a taste, let's get to the details.

What Dynamator is

Dynamator is a language that specifies how to transform an HTML or XML file into a server page or program, and a tool for performing the transformation.

Template files

The file that Dynamator operates on is called a template. Templates must be XML. Dynamator converts HTML to XML using JTidy, a Java port of Tidy. It's a good idea to validate HTML using Tidy before using it with Dynamator.

Examples in this guide use HTML; XML works the same way.

Dynamator files

A Dynamator file describes how to transform a template file into a server page or program. For any template file x.html or x.xml, the Dynamator file is named x.dyn.

Programming Language Support

Dynamator uses language-specific plugins to format the output file. Dynamator ships with plugins for JSP, XSL, PHP, ASP, and Java. Plugins for other languages are easy to write and install.

Dynamator also ships with a plugin for an imaginary language named "none", that provides default support for stream-oriented template languages (such as Velocity) as well as HTML and XML. The default plugin supports all Dynamator elements that don't require knowledge of the target language. Elements that require a language plugin are <content>, <if>, <for>, and <foreach>. Equivalent constructs can be coded manually using low-level Dynamator elements.

The examples in this guide use JSP, but the Dynamator element syntax is the same regardless of language.

Marking up HTML and XML

Dynamator needs some way to identify locations in the HTML or XML template. It uses two standard HTML 4.0 attributes: id (used to identify a single location in an HTML file) and class (used to identify a set of locations in an HTML file).

In general, every HTML element that needs to be changed in some way needs an id or class attribute. However, some HTML elements (such as <body> and <meta> do not support these attributes. Dynamator also provides a way to identify these elements so they can be changed.

Sometimes there is no element at a location that needs to be changed. HTML 4.0 also defines two elements that can be used in this situation: span (an in-line element that can contain in-line content) and div (a block element that can contain block or in-line content).

All these features are invisible; they do not affect the appearance of the HTML. (The div element implies a line break; if this is not desired Dynamator can remove the tag.)

HTML authors are familiar with these features of HTML because they use them with CSS.

Here's a simple example that shows the use of span:

TheTime.html
<html>
<head>
<title>What time is it?</title>
</head>
<body>
<p>The time is 
<span id="Now">[time goes here]</span>
</body>
</html>
TheTime.dyn
<dynamator language="jsp">
  <id name="Now">
    <content>new java.util.Date()</content>
  </id>
</dynamator>
 
TheTime.jsp
<%-- generated by Dynamator Fri Nov 23 17:52:49 CST 2001
                           --%><html>
  <head>
    <title>What time is it?</title>
  </head>
  <body>
    <p>The time is <span id="Now"><%= new java.util.Date() %></span></p>
  </body>
</html>

Dynamator file syntax

Dynamator files use XML syntax, with the following important exceptions:

  • Programmatic elements can contain invalid content. So, for instance, you can write x < y instead of <![CDATA[x < y]]>.
  • XML entities are not resolved. Instead, entities are passed through unchanged to the output.

These exceptions simplify coding, and are similar to the kinds of exceptions made by languages such as JSP.

A Dynamator file contains the changes to be applied to a template file. The structure of the file mirrors a two step process:

  1. Identify a set of locations that need to be changed.
  2. Specify the changes to be made at those locations.

Root Level

Here's an empty Dynamator file:

<dynamator language="jsp">
</dynamator>

Every Dynamator file must start and end with a <dynamator> element. The language attribute is required; it specifies the language of the server page or program to be created, and controls the behavior of language-specific elements such as <foreach> and <if>. Other supported languages include java, xsl, php, and asp.vb. When the language is java, the output is a Java program that uses out.print to output template content.

First Level: Locators

Most elements at the first level of the Dynamator file identify locations in the template file. These elements are called locators. Here's a Dynamator file showing the most important first-level elements:

<dynamator language="jsp">

  <prolog>
    This text is inserted at the beginning of the file
  </prolog>
  
  <id name="idname">
    <!-- This locator matches any template element with the
            attribute id="idname" -->
  </id>

  <class name="classname">
    <!-- This locator matches any template element with the
            attribute class="classname" -->
  </class>

  <tag tag="tagname">
    <!-- This locator matches any template element with the
            name tagname -->
  </tag>

  <include file="filename"/>
    <!-- This element includes the contents of
            the Dynamator file filename -->

  <epilog>
    This text is inserted at the end of the file
  </epilog>

</dynamator>

File prolog and epilog

The <prolog> and <epilog> elements allow text to be placed at the very top and bottom of the output file. Text within these elements is copied as-is, including white-space. If you don't want white space, don't use any:

<dynamator language="xsl">
  <prolog><?xml version="1.0"></prolog>
</dynamator>

Locating elements by key

The <id> and <class> elements locate template elements by key.

Locating elements by id name

The <id> element locates each template element that has a matching id attribute. For example:

id_example.html
<html>
...
<h1 id="title-heading">Title</h1>
...
</html>
id_example.dyn
<dynamator language="jsp">
  <id name="title-heading">
    <content>titleHeading</content>
  </id>
</dynamator>
 
id_example.jsp
...
<html>
...
<h1 id="title-heading"><%= titleHeading %></h1>
...
</html>
...

The <id> element in the example Dynamator file above matches every template element that has the attribute id="heading".

(In a valid HTML document, there is at most one occurrence of any id attribute value.)

Locating elements by class name

The <class> element locates each template element that has a matching class attribute. For example:

class_example.html
<html>
...
<h1 class="subject-name">Subject</h1>
...
<h2>Summary for 
<span class="bold subject-name">Subject</span>:</h2>
...
</html>
class_example.dyn
<dynamator language="jsp">
  <class name="subject-name">
    <content>subject.getName()</content>
  </class>
</dynamator>
 
class_example.jsp
...
<html>
...
<h1 class="subject-name"><%= subject.getName() %></h1>
...
<h2>Summary for 
<span class="bold subject-name"><%= subject.getName() %></span>:</h2>
...
</html>
...

The <class> element in the example Dynamator file above matches every template element that has the attribute class="subject-name".

Note that the second template element above belongs to two classes, bold and subject-name.

Locating elements by name and attributes

Sometimes an HTML element can't legally have an id or class attribute. For example, id and class attributes are invalid for elements in the <head> section. So Dynamator also provides the tag locator, which can be used to locate a set of elements based on tag name and attributes.

Here are some examples of the tag locator:

<tag tag="td"> applies to all <td> elements in the template.
<tag tag="meta" http-equiv="Refresh"> applies to all <meta ...> elements in the template with the attribute http-equiv="Refresh".
<tag tag="a" with-attr="href"> applies to all <a href="..."> elements, but no <a name="..."> elements.
<tag tag="*" with-attr="class"> applies to all elements that have a class attribute.

The <tag> element is extremely powerful. In fact, it could replace the <id> and <class> elements completely. For example, <tag tag="*" class="some-class"> is equivalent to <class name="some-class">. Where possible, though, you should prefer <id> or <class> to <tag>.

Including other files

Dynamator provides a file include mechanism to enable reuse. The <include> element logically inserts the contents of another Dynamator file into the including file. An <include> element may only be used at the top level, and the included file must be a Dynamator file.

By default, Dynamator uses the directory containing the initial Dynamator file as the basis for resolving relative filenames.

You can specify a search path using the command line option "-I dir". If multiple -I arguments are provided, each directory is tried in order. If the file isn't found in any of the include directories, the directory containing the top-level Dynamator file is tried.

Second Level: Modifiers

The content of a locator specifies the changes to be made to the located element. Elements within a locator are called modifiers.

Here's a locator element with the most frequently used modifiers. Note that these modifiers apply to the <class> and <tag> locators as well as <id>.

<id name="idname">

  <content>
    A program expression to be output instead of the element's content.
  </content>    

  <raw-content>
      Text or code that replaces the attribute value.
  </raw-content>    
    
  <discard/>
    <!-- Removes the element and its content -->

  <discard-tag/>
    <!-- Removes the element's start and end tags but not its content -->

  <attr name="attrname">
    <!-- Attribute modifiers, described below. -->
  </attr>
  
  <rename to="element-name"/>
    <!-- Renames the element -->
  
  <!-- ========================================
       Language-specific elements:
       These elements require a language plugin.
       ======================================== -->
  <if>
    A program conditional expression.
    The template element is output only if the condition is true.
  </if>

  <foreach>
    A program collection expression.
    The template element is output for each element of the collection.
  </foreach>

</id>

The <content> element contains a program expression (often a variable reference). Dynamator replaces the content of the template element with code to output the value of that expression. We've already seen examples of the <content> element in the helloworld and time examples.

The <content> element uses the language-specific plugin to determine the appropriate expression reference syntax for the target language. (For JSP, the expression syntax is <%= expression%>.) If no plugin is available for the target language, element content is used as-is. If working with a language for which there is no plugin, it's best to use the <raw-content> element instead.

The <raw-content> element works like <content>, except that its content is used as-is. The <raw-content> is rarely used when a language-specific plugin is available.

The <discard/> element causes the entire matched element to be removed (from the start-tag to the end-tag, including everything in between). This is useful for removing sample data from a demonstration site. The <discard-tag/> element causes just the matched start and end tags to be removed, leaving the element content.

The <rename> element causes the matched element to be renamed. This is useful for JSP tag libraries and ASP.NET, which use pseudo-HTML elements.

If

The if element generates code to cause an element to be output only if a condition is true.

The following Dynamator example uses if to generate a greeting appropriate for the time of day.

TimeGreeting.html
<html>
<head>
<title>What time is it?</title>
<span type="text/css">
.hide { display: none }
</span>
</head>
<body>
<p>The time is 
<span id="Time">[time]</span></p>
<p id="Morning">Good Morning!</p>
<div class="hide">
<p id="Afternoon">Good Afternoon!</p>
<p id="Evening">Good Evening!</p>
</div>
</body>
</html>
TimeGreeting.dyn
<dynamator language="jsp">
<prolog>
<%@ page import="java.util.Calendar"%>
<%
    Calendar calendar = 
        Calendar.getInstance();
    int hour = calendar.get(
        Calendar.HOUR_OF_DAY);
%>
</prolog>
<id name="Time">
  <content>calendar.getTime()</content>
</id>
<id name="Morning">
  <if>hour < 12</if>
</id>
<id name="Afternoon">
  <if>12 <= hour && hour < 18</if>
</id>
<id name="Evening">
  <if>18 <= hour</if>
</id>
<class name="hide">
  <discard-tag/>
</class>
</dynamator>
 
TimeGreeting.jsp
<%-- generated by Dynamator Sat Nov 24 10:02:26 CST 2001
--%>
<%@ page import="java.util.Calendar"%>
<%
    Calendar calendar = 
        Calendar.getInstance();
    int hour = 
        calendar.get(Calendar.HOUR_OF_DAY);
%>
                           <html>
    <head>
    <title>What time is it?</title>
  </head>
  <body>
    <p>The time is <span id="Time"><%= new Date() %></span></p>
<%
      if ( hour < 12 ) 
      {
        %><p id="Morning">Good Morning!</p><%
      }
                               %>
<%
      if ( 12 <= hour && hour < 18 ) 
      {
        %><p id="Afternoon">Good Afternoon!</p><%
      }
                               %>
<%
      if ( 18 <= hour ) 
      {
        %><p id="Evening">Good Evening!</p><%
      }
                               %>
  </body>
</html>

The example above shows a pattern that can be used for handling selective display of text defined in a template. The template contains all the text, but displays only the text associated with a single condition. This is so the template can be used in a static demo site. (You can get a lot more sophisticated in a demo site if you want.) The Dynamator file makes all elements potentially visible--in this case by removing the <div class="hide"> start and end tags using the <discard-tag/> element, and wraps each selection in an <if>.

Note a difference here from how you would hand-code this: Dynamator does not support else. (Supporting else would make the Dynamator file dependent on the sequence of the entries in the HTML file.) You can always use Dynamator's <before> or <after> elements to insert an else; just be aware that this will make your code a little more brittle.

Foreach

The foreach element generates code to repeat the located template element for each element of a collection. The attributes used depend on the language. The following example outputs each item in the classpath.

Classpath.html
<html>
<head>
<title>Java Classpath</title>
</head>
<body>
<h1>Classpath:</h1>
<p class="pathelem">
(element)
</body>
</html>
Classpath.dyn
<dynamator language="jsp">
  <prolog>
    <%@ page import="java.util.StringTokenizer"%>
  </prolog>
  <class name="pathelem">
    <foreach 
        type="Enumeration[String]" 
        collection="tokens"
        element="dir"
        >
      new StringTokenizer(
          System.getProperty("java.class.path"), 
          System.getProperty("path.separator"))
    </foreach>
    <content>
      dir
    </content>
  </class>
</dynamator>
 
Classpath.jsp
<%-- generated by Dynamator Fri Nov 23 11:11:46 CST 2001
--%>
    <%@ page import="java.util.StringTokenizer"%>
<html>
  <head>
    <title>Java Classpath</title>
  </head>
  <body>
    <h1>Classpath:</h1>
    <%
      {
        java.util.Enumeration tokens = new StringTokenizer(
          System.getProperty("java.class.path"), 
          System.getProperty("path.separator"));
        String dir;
        while ( tokens.hasMoreElements() )
        {
          dir = (String) tokens.nextElement();
    %>
                                   <p class="pathelem"><%= dir %></p>>
    <%
        }
      }
    %>
                             </body>
</html>

Attribute Modifiers

Attributes can be changed, added, removed, and made conditional.

Here's a locator element with all possible attribute modifiers.

<id name="idname">
  <attr name="attrname">

    <content>
      A program expression to be output instead of the attribute value.
    </content>    
  
    <raw-content>
      Text or code that replaces the attribute value.
    </raw-content>    
    
    <discard/>
      <!-- Removes the attribute -->
  
    <rename to="attr-name"/>
      <!-- Renames the attribute -->
  
    <!-- ========================================
         Language-specific elements:
         These elements require a language plugin.
         ======================================== -->
    <if>
      A program conditional expression.
      The attribute is output only if the condition is true.
    </if>

  </attr>
</id>

If an <attr> element contains a content or raw-content entry, and the corresponding attribute is not found in the template, it is added.

Text can also be added directly to a tag using the raw-attrs modifier.

Within the content and raw-content entries for an <attr> element, the magic string [[@]] stands for the original attribute value, and the magic expression [[@/x/y]] stands for the original attribute value with all occurrences of the string 'x' replaced by 'y'. This comes in handy when converting HTML links to server pages links:

Menu.html
<html>
<head>
  <title>Menu</title>
</head>
<body>
<a href="page1.html">Page 1</a>
<br>
<a href="page2.html">Page 2</a>
<br>
<a href="page3.html">Page 3</a>
<br>
<a href="page4.html">Page 4</a>
</body>
</html>
Menu.dyn
<dynamator language="jsp">
<tag tag="a" with-attr="href">
  <attr name="href">
    <content>
      response.encodeURL("[[@/.html/.jsp]]")
    </content>
  </attr>
</tag>
</dynamator>
 
Menu.jsp
<%-- generated by Dynamator Sat Nov 24 10:55:37 CST 2001
--%><html>
  <head>
    <title>Menu</title>
  </head>
  <body>
   <a href="<%= 
      response.encodeURL("page1.jsp")
                               %>">Page 1</a><br>
   <a href="<%= 
      response.encodeURL("page2.jsp")
                               %>">Page 2</a><br>
   <a href="<%= 
      response.encodeURL("page3.jsp")
                               %>">Page 3</a><br>
   <a href="<%= 
      response.encodeURL("page4.jsp")
                               %>">Page 4</a><br>
  </body>
</html>

Primitive Modifiers

Primitive modifiers support low-level changes to a template. You shouldn't need to use them very often. If you are generating to an unsupported template language, you can use primitive modifiers to manually create if and foreach logic. (Better yet, create a plugin and save yourself some time.)

Here's a locator element showing all the primitive modifiers. Note that these modifiers apply to the <class> and <tag> locators as well as <id>.

<id name="idname">

  <before>
    Text or code inserted immediately before the element's start tag
  </before>    

  <before-content>
    Text or code inserted immediately after the element's start tag
  </before-content>    

  <raw-content>
    Text or code that replaces the element's content.
  </raw-content>    

  <after-content>
    Text or code inserted immediately before the element's end tag
  </after-content>    

  <after>
    Text or code inserted immediately after the element's end tag
  </after>    

  <raw-attrs>
    <!-- Text or code added to the element's start tag. -->
  </raw-attrs>

</id> 

Here's the placement relationship of the primitive elements to the located element in the generated server page:

   before
                           <located-element raw-attrs>
   before-content
                             element content or content or raw content
   after-content
                           </located-element>
   after
                           

Locator Precedence

If an element is addressed by multiple locators, locators are applied in the following order:

  1. <id> locators.
  2. <class> locators.
  3. <tag> locators.

If more than one of any kind of locator (for example, two <tag> locators) matches the same element, they are applied in the order they appear in the Dynamator file.

Regardless of how many locators match, only one of each kind of modifier is applied. Attribute modifiers are distinguished by attribute name, so if locator 'a' has an attribute modifier for attribute 'x', and locator 'b' has an attribute modifier for attribute 'x' and attribute 'y', locator 'a's modifier for 'x' will be applied, and locator 'b's modifier for 'y' will be applied.

Where to go from here

You now should have a basic understanding of Dynamator facilities for creating server pages and programs. Some possible next steps:

  • Take a look at some examples.
  • Try Dynamator for yourself by following the directions in the Quick Start.
  • Find out how to use Dynamator for internationalization by reading the internationalization guide.
  • Learn more about using Dynamator with HTML and XML by downloading the documentation and reading through the Dynamator tutorial.