Introduction

We've defined a pair of macros which enable a program to generate html
in a concise and readable manner. These macros are quite a bit different
than those found in other html generation systems and thus we'll briefly
describe the justification for this design.

html is a concise markup language. There is a tendency in language
design to assume that one's users won't be as smart as one's self and thus one tends to
dumb things down. For example, html uses <p>
to start a paragraph. The language designer says to himself: "while I
know that p means paragraph, my users won't so I'll spell it out as with-paragraph."
A similar thing is done for all the other html commands and soon a program to
generate html contains so many long markup commands that it's hard to see the text of the
document from the markup commands. A second problem is that as a user you're not
sure exactly what html will be generated by some high level with-xxx
forms. If you're trying to generate a particular sequence of html
you're left experimenting with the high level forms and hoping that by luck you get the
output you want. A third problem is that with the high level forms
you're forced to learn yet another markup language. There are plenty of books and
reference guides to html itself and it's an easy language to master.
Learning a particular high-level mapping of html is an
added burden.

With our html generation macros you write the actual html and
we just eliminate some of the tedious parts, such as closing off markup commands.
The result is that the structure of the document is visible and you can use any book on html
as a reference.

Example

The following example of a generated web page will be useful to refer to in the
discussion below of the syntax of the html macro.

This particular example generates a complete web page, but it's possible to use the
html macro to generate partial pages as well. In this
example, the generated page is surrounded by <html> and </html>
due to the :html form. The page contains a header and a
body surrounded by their respective html markers. The body of the document contains
a level 1 header followed by the text beginning "Hello, AllegroServe".
Following that is printed the universal time at the time that the page is
generated (i.e now rather than when the macro was first processed by lisp).
The following incf expression is evaluated but the result is not
printed. In this case we're keeping a private count of the number of times
this page has been accessed.

html macro

Now that you have a sense of how the html macro works, we will
describe the syntax in detail.

(html form1 form2 ... formn)
[Macro]

The forms are processed from left to right. The most likely effect is that
html output is generated. The output is sent to the stream net.html.generator:*html-stream*.
The html macro is designed to run inside AllegroServe's with-http-body
macro which binds *html-stream* to the correct stream. Also
the html-stream macro described below binds *html-stream* before
calling html. The action taken by html depends on
what the form looks like at macro-expansion time. The possibilities are:

string - A string is simply written (using princ) to the output
stream. Thus the string could contain embedded html commands.

keyword symbol - The keyword must name a known html operator. The
result is that the associated html markup command is sent to the output stream. The
mapping of keyword to html command is trivial -- the print name of the keyword is the html
command. So :p emits <p>.

list beginning with a keyword symbol - This names an html operator that
may or may not have an associated inverse operator beginning with "/". The
typical result of this form is to emit the associated html markup command, then process
the items in the list in the same way as the forms are processed, and then emit the
inverse markup command. Thus (:i "foo") emits <i>foo</i>.
There is a special case when a single element list is given
(see below for details). Also there are some special keywords that are commands to
the html macro rather than markup commands. They are described
below.

list beginning with a keyword symbol - This is used to specify
markup commands that have parameters. For example ((:a href "/foo/bar.html") "the link") turns into <a
href="/foo/bar.html">the link</a>. The
arguments are in plist form: a sequence of names and values. The names are not
evaluated, they should be symbols or strings. We often use keyword symbols for
the names since that looks more lisp-like and reduces the number of symbols we create.
The values are evaluated and printed with a function that escapes
characters with special meaning in html : <, >, &, ". If the
value is a symbol with a zero length print name, then something special is done: The
name alone is printed without a following equal sign. For example: ((:option
:size 4 :selected '||) "foo") generates <option
size="4" selected>foo</option>. This form of
valueless argument is illegal html but in some older browsers it's the required syntax.

anything else - everything else is simply evaluated in the normal lisp way and the
value thrown away.

Special cases:

(:princ arg1 arg2 .. argn) causes the result of
evaluating each of the args to be printed to the html stream using the princ
function (which prints without inserting escape characters needed by the lisp reader to
read the result).

(:prin1 arg1 arg2 ... argn) causes the result of
evaluating each of the args to be printed to the html stream using the prin1 function
(which prints by inserting escape characters needed by the lisp reader to read the
result).

(:princ-safe arg1 arg2 .. argn) acts like the :princ
case except that the output is scanned for characters that could be considered html markup
commands, and if found, these characters are escaped to prevent them from being treated as
html markup commands.

(:prin1-safe arg1 arg2 .. argn) acts like the :prin1
case except that the output is scanned for characters that could be considered html markup
commands, and if found, these characters are escaped to prevent them from being treated as
html markup commands.

:newline simply inserts a newline into the html output stream.
This will not have an effect on the result as viewed by a web browser (unless
it is emitted while inside an html markup command that specifies preformatted input).
The main use for this is to make the resulting html file easier to read by a human.

You can conditionally specify arguments to a markup command using an argument name of
:if*. Following the :if* is a lisp expression
which if true at runtime will cause the following argument value pair to be included in
the argument tag. For example ((:td :if* (frob) :bgcolor
"#00ff00") "xx") will only put bgcolor="#00ff00"
in the argument if the expression (frob) returns true at runtime.

(html-stream streamform1 form2 ...
formn)
[Macro]

This binds net.html.generator:*html-stream* to the value of the stream
argument and then evaluates the formarguments just like the html
macro.

Examples

We will show how to build a page containing a table using successively more runtime
customization of the table. First we show how to build a table of squares.

It isn't very pretty but it's easy to see the correspondence between the html
macro and the resulting table. Note that if we had done, for example, (:td
1) instead of (:td "1") then nothing would have been
emitted. Only constant strings are printed, not constant integers. To
use an integer here we would have had to do (:td (:princ 1)).

We can use the ability to pass arguments to html markup commands to specify a border
around the elements of the table as shown here:

Suppose we wanted to make the table include the squares of numbers from zero to 100.
That would take a lot of typing. Instead, let's modify the table generation
function to compute a table of any size:

Note that we can freely imbed calls to the html macro within another
call. The dotimes call inside the :body
expression is simply evaluated and its value ignored. However the side effect of the
dotimes is to generate more html and to send it to the stream bound in
the html-stream call. The result of (simple-table-c
8) is

0

0

1

1

2

4

3

9

4

16

5

25

6

36

7

49

We can specify at runtime values for the arguments to html markup forms. This
function allows us to specify parameters of the table being built:

This sets the color of the columns to alternately red and green: Here is (simple-table-e 6)

0

0

0

0

0

0

0

1

2

3

4

5

0

2

4

6

8

10

0

3

6

9

12

15

0

4

8

12

16

20

0

5

10

15

20

25

HTML generation functions

It's possible to express HTML using Lisp data structures. The form is based
on how HTML is written using the html macro above.

Lisp HTML (lhtml) is defined as one of the following

a string, which is rendered as HTML by simply printing it. Thus the string can
contain embedded HTML commands.

a list beginning with a valid lhtml keyword and containing lhtml
forms. The valid keywords are those corresponding to the HTML entity tags,
plus the special tags :princ, :princ-safe, :prin1, :prin1-safe, :newline
and :comment. These act just as they do in the html
macro. This form is rendered as an opening tag, then the rendering of the
body, and a closing HTML tag if one exists.

a list beginning with an lhtml keyword.
This is the form used when attributes are to be supplied with the opening entity
tag.

Examples of valid lhtml:

"foo<i>bar</i>baz"

(:i "foo")

((:body :bgcolor "#xffffff") "the body")

(html-print lhtml stream)

Print the Lisp HTML expression lhtml to the stream.

(html-print-list lhtml-list stream)

Print the list of lhtml forms to the stream. This
is equivalent to calling html-print on every element of lhtml-list.