1 Introduction
2 Interface
3 History
4 Legal
Version: 2:2

html-template: HTML-Writing Template Language for SXML/xexp in Racket

Neil Van Dyke

 (require (planet neil/html-template:2:2))

1 Introduction

The html-template package implements an HTML-writing template language based on SXML/xexp. Compared to doing comparable work using the html-writing package, html-template offers improved compile-time error-checking, arguably better readability of code, and possibly improved run-time efficiency. Uses of html-template are often mixed with uses of the html-writing package.
For example:
(define (write-essay my-title)
    (html (head (title (% my-title)))
          (body (h1 (% my-title))
                (p "Kittens claw."
                   "Puppies pee.")))))
(write-essay "All About Kittens & Puppies")
produces the output:

<html><head><title>All About Kittens &amp; Puppies</title></head><body><h1>All About Kittens &amp; Puppies</h1><p>Kittens claw.<br>Puppies pee.</p></body></html>

Expanding that use of the html-template macro in this case results in something like:
(let-values (((out) (current-output-port)))
  (parameterize ((current-output-port
    (write-bytes #"<html><head><title>" out)
    (%html-template:format/content/write my-title out)
    (write-bytes #"</title></head><body><h1>" out)
    (%html-template:format/content/write my-title out)
    (write-bytes #"</h1><p>Kittens claw.<br>Puppies pee.</p></body></html>" out)
Observe that much of the computation for HTML formatting is done at compile time rather than at run time.
By design, the html-template has no special syntax for behavior such as iterating over the rows of an SQL query result. Instead, it provides template escape syntax that supports pieces of arbitrary Racket code to be inserted into the template to perform behavior such as this. The different template escapes provide different ways for the Racket code to produce HTML. For example, the %write escape can be used to have a “nested” use of html-template, such as for formatting each row of a table for each row of a database query result:
  (html (h1 "People")
        (p "The people are:")
        (table (@ (border "1"))
               (tr (th "Name") (th "Color"))
                (for-each (lambda (person)
                              (tr (td (% (person-name  person)))
                                  (td (% (person-color person))))))
        (p "Fin.")))
Given some particular value for people, this produces the output:

<html><h1>People</h1><p>The people are:</p><table border="1"><tr><th>Name</th><th>Color</th></tr><tr><td>Juliette</td><td>Blue</td></tr><tr><td>Zbigniew</td><td>White</td></tr><tr><td>Irene</td><td>Red</td></tr></table><p>Fin.</p></html>

The different template escapes are discussed in more detail in the documentation for the html-template form.
Note that application programmers don’t necessarily call html-template directly very often. Programs for Web sites with particular conventions for page layout might define their own macros for their own conventions, which then expand to uses of html-template.

2 Interface

The interface in this version of the package is the html-template form.


(html-template maybe-port content ...+)

maybe-port = 
  | #:port output-port-or-false
content-context = element
  | string?
  | bytes?
  | escape
element-context = element
  | escape
element = (symbol? maybe-attributes content-context ...)
maybe-attributes = 
  | (@ attribute-context ...+)
attribute-context = attribute
  | escape-except-format
attribute = (symbol? attribute-value-context ...+)
attribute-value-context = string?
  | bytes?
  | escape
escape = escape-except-format
  | (%format expr ...+)
  | (%       expr ...+)
escape-except-format = (%verbatim       expr ...+)
  | (%write          expr ...+)
  | (%write/port var expr ...+)
  | (%void           expr ...+)
Write the SXML/xexp template as HTML bytes to the output port specified by #:port, or, if that is #f, to current-output-port (the default). The UTF-8 encoding is used. The template consists of literal SXML/xexp, and of template escapes with names beginning with %.
The template escapes each permit Racket expressions, exprs, to be evaluated during the generation of HTML at that point in the template, sequenced like begin. The differences between the template escapes concern what is done with the value of the sequence of expressions, such as whether the value is to be output literally as part of the HTML or to be further processed as SXML/xexp, and with what happens to writing to current-output-port. Specifically, the escapes and their meaning are:
  • (%xexp expr ...) and (%sxml expr ...) expr evaluates to an SXML/xexp value, which is output as HTML in the appropriate context (e.g., content context vs. attribute value context).

  • (%format expr ...) and (% expr ...) expr evaluates to some value, and this value is formatted for appropriate literal display in HTML. For example, a string value is displayed as text, an integer value is displayed as a number, a date object is displayed as a date, etc. The formatting handler is customizable by the application programmer. (Note that the meaning of % changed purposes in PLaneT version 2:0 of this package: in version 1:1, it was similar to the current %xexp, rather than being shorthand for %format.

  • (%verbatim expr ...) expr evaluates to bytes, string, or a list of byteses and/or strings, which are output verbatim as bytes.

  • (%write expr ...) expr is evaluated, and any writes to current-output-port are added verbatim to the output. Note that %write and %write/port are the only template escapes that permit writing directly to a port that goes to HTML output.

  • (%write/port var expr ...) Like %write, except that writing must be to the output port var. Writing to current-output-port within %write/var will raise an error, on the assumption that it’s most likely a bug (like a missing port parameter in a display, printf, or nested html-template).

  • (%void expr ...) expr is evaluated, and any value is ignored. This is used for side-effects.

Note that %write is the only escape that permits an expr to write to current-output-port an error will be raised in all other escapes.

3 History

4 Legal

Copyright 2011 – 2012 Neil Van Dyke. This program is Free Software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. See http://www.gnu.org/licenses/ for details. For other licenses and consulting, please contact the author.