seethrough: a simple XML/XHTML templating system for Erlang

Speaking of winter evenings, a couple of weeks ago over Christmas I spent a few hours whipping together a simple templating system for Erlang.

Today I took another couple of hours to put it under version control and to add some ideas I found in ZPT, a similar system (hat tip to Jérôme for pointing it out).

This is how it works: you start with an XHTML (or any XML) file with some extra attributes thrown in and properly namespaced:


<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:e="http://dev.hyperstruct.net/seethrough">
  <head>
    <title e:content="title"/>
  </head>
  <body>
    <h1 e:content="title"/>

    <h2><span e:replace="subtitle"/></h2>

    <table>
      <thead>
        <tr>
          <th>Address</th>
          <th>Name</th>
        </tr>
      </thead>
      <tbody>
        <tr e:repeat="crew">
          <td e:content="address"/>
          <td e:content="name"/>
        </tr>
      </tbody>
    </table>
  </body>
</html>

Since it is a valid document, even designers can load it into their WYSIWYG editors and be happy.

Next, you pass the file name along with an environment (a list of key/value tuples) to apply_template/2:


seethrough:apply_template("test.html",
    [{title, "Space"},
     {subtitle, {mymod, get_subtitle, []}},
     {crew, {mymod, get_crew, []}}])).

Given such input and such environment:

  • <h1 e:content="title"/> will be replaced by <h1>Space</h1>.
  • <span e:replace="subtitel"/> will be replaced by the result of mymod:get_subtitle/0.
  • <tr e:repeat="crew">...</tr> will be repeated as many times as there are elements in the (list-)result of mymod:get_crew/0.

Here is the output:


<?xml version="1.0"?>
<html xmlns:e="http://dev.hyperstruct.net/seethrough"
      xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>Space</title>
  </head>
  <body>
    <h1>Space</h1>

    <h2>The last frontier...</h2>

    <table>
      <thead>
        <tr>
          <th>Address</th>
          <th>Name</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>kirk@enterprise.glx</td>
          <td>Jim</td>
        </tr><tr>
          <td>spock@enterprise.glx</td>
          <td>Spock</td>
        </tr><tr>
          <td>mccoy@enterprise.glx</td>
          <td>Doc</td>
        </tr>
      </tbody>
    </table>
  </body>
</html>

Only a tiny part of ZPT (basically, what is needed in the above example) is mirrored so far. While I will bring more of it in, since it is obviously well designed, this will not be a port, partly because Erlang is not Python and there might be other good design choices around the corner, partly because I spent some time generating XHTML in Erlang the usual way ({body, [], [{p, [], [...]}], gen_table(...)}) and while it might not be the most familiar thing in the world, dealing with XML generation as function composition is fascinating and it would be nice to bring that into the picture.

The code is available at http://repo.hyperstruct.net/seethrough.

Update 13/01: Nevow XML Templates provide more excellent inspiration.

Update 17/01: The <attr> tag á la Nevow has been added (it affects attributes of the parent element). A project page is also available at http://hyperstruct.net/projects/seethrough, please see that for an updated example of template processing.

Update 13/02: Now with sub-templates and cache-ready.

Share
  • Trackbacks are closed
  • Comments (5)
    • Tobbe
    • March 4th, 2007

    Hi,

    Just checking by. I was wondering if you have read this excellent paper:

    http://www.cs.usfca.edu/~parrt/papers/mvc.templates.pdf

    Cheers, Tobbe

  1. Makes me think of the following templates languages in PHP, maybe you’ll get more inspiration.

    http://phptal.motion-twin.com/introduction.html

    http://www.tinybutstrong.com/examples.php

  2. More food for thought. Thanks!

    • yrn1
    • June 23rd, 2007

    I’ve been using ZPT a lot a while ago, and once I got used to it, thought it was the most sane templating system I’ve seen. Getting this for Erlang is excellent. Keep up the good work ;-)

    • merl
    • June 18th, 2008

    These examples (here and from http://hyperstruct.net/projects/seethrough) are just not working.
    -module(tt).
    -import(seethrough, [apply_template/3]).
    -compile(export_all).

    test() ->
    io:format(
    seethrough:apply_template({file, “test.html”},
    [{title, "Space"},
    {alignment, "center"},
    {subtitle, {?MODULE, get_subtitle, []}},
    {background_color, “blue_skies”},
    {crew, {? MODULE, get_crew, []}}])).

    get_subtitle() ->
    “The final frontier…”.

    get_crew() ->
    [[{address, "kirk@enterprise.glx"},
    {name, "Jim"}],
    [{address, "spock@enterprise.glx"},
    {name, "Spock"}],
    [{address, "mccoy@enterprise.glx"},
    {name, "Doc"}]].

    Running:

    80> tt:test().
    ** exception error: no function clause matching
    proplists:lookup_all(address,{tt,get_crew,[]})
    in function env:lookup/3
    in call from seethrough:lookup/3
    in call from seethrough:’-compile/2-fun-0-’/5
    in call from seethrough:’-exec/2-lc$^0/1-0-’/2
    in call from seethrough:’-exec/2-lc$^0/1-0-’/2
    in call from seethrough:exec/2
    in call from seethrough:’-compile/2-fun-9-’/4

Comments are closed.