Using with-lhtml-string
<-Previous | ^UP^ | Next->
LHTML is a Markup Language included in Gendl (standing for Lisp HTML) which provides a convenient way to generate html using lisp-like expressions. It is intended to be portable and shoud work with all ANSI standard Common Lisp Implementations.
The main element of lhtml is the macro with-lhtml-string, which transforms its body into a html string
In general, we use with-lhtml-string when creating html strings for use in GWL web pages
with-lhtml-string takes an optional input :indent. By default it is nil which results in html with no unnecessary whitespace to minimise the bandwith being used. But for debugging purposes, the resulting html may be difficult to read. Setting :indent to t causes line breaks to be inserted and nested tags properly indented
GWL-USER (with-lhtml-string ()(:table (:tr (:td))))"<table><tr><td></td></tr></table>"GWL-USER (with-lhtml-string (:indent t)(:table (:tr (:td))))"<table> <tr> <td></td> </tr></table>"
Markup
To generate html we use a nested list of s-expressions. Each list beginning with a keyword is transformed into a html tag of the same name by the following rules:
- If the list contains nothing but a keyword an empty element is written
GWL-USER (with-lhtml-string()(:br))<br />
- If the keyword is followed by another keyword, it's interpreted as an attribute and the next form is the value of that attribute
GWL-USER (with-lhtml-string()(:span :class "myclass"))"<span class="myclass"></span>"
- Multiple attribute-value pairs may be specified
GWL-USER (with-lhtml-string()(:table :border 1 :cellspacing 3 :cell-padding 5))"<table border="1" cellspacing="3" cell-padding="5"></table>"
- The first form which isn't a keyword and follows either the tag or an attribute value is interpreted as the tag content
GWL-USER (with-lhtml-string()(:p "This is content"))"<p>This is content</p>"GWL-USER (with-lhtml-string()(:span :class "myclass" "This is more content"))"<span class="myclass">This is more content</span>"
- To make it slightly easier to read, the tag and all attribute-value pairs may be enclosed in an additional list, but this is purely optional
GWL-USER (with-lhtml-string()(:span :class "myclass" "This is more content"))"<span class="myclass">This is more content</span>"GWL-USER (with-lhtml-string()((:span :class "myclass") "This is more content")))"<span class="myclass">This is more content</span>"
- Tags may be embedded in other tags
GWL-USER (with-lhtml-string()(:table :border 1(:tr(:td "Cell 1")(:td "Cell 2"))))"<table border="1"><tr><td>Cell 1</td><td>Cell 2</td></tr></table>"
Markup with computed content
So far any tag content we have shown is static, so how do we handle computed content? If we just wish to output the value of a slot, we must wrap that slot with the macro str
GWL-USER (let ((cell-1 "Cell 1 content")(cell-2 "Cell 2 content"))(with-lhtml-string ()(:table (:tr (:td (str cell-1)) (:td (str cell-2))))))"<table><tr><td>Cell 1 content</td><td>Cell 2 content</td></tr></table>"
If we want to present the value of a slot with some formatting, rather than use the format function to format the value of the slot, we could wrap the value in the macro fmt, which takes the same directives as the formatfunction
GWL-USER (let ((cell-1 1)(cell-2 2))(with-lhtml--string ()(:table (:tr (:td (fmt "Cell ~a content" cell-1)) (:td (fmt "Cell ~a content" cell-2))))))"<table><tr><td>Cell 1 content</td><td>Cell 2 content</td></tr></table>"
It is also possible to embed any type of Lisp processing within the body of with-lhtml-string, although whenever we break out of the html generation to do some processing, once we restart html generation again we need to wrap the html generation in the htm macro
GWL-USER (with-lhtml-string ()(:table (:tr (let ((lis (list 1 2)))(dolist (a lis)(htm (:td (fmt "Cell ~a" a))))))))"<table><tr><td>Cell 1</td><td>Cell 2</td></tr></table>"
Finally, a word of warning. lhtml knows nothing about html, it just processes what it is given according to the rules above. So there is no checking to see if the first keyword is a valid html tag, or if the second keyword is a valid tag attribute. Thats your job!