From: Andreas Thiele
Subject: easily embedding html into Lisp
Date: 
Message-ID: <ci95od$jvc$05$1@news.t-online.com>
I'd like to introduce a simple approach of embedding html into Lisp.

Let's consider the following call to format

(format nil "~{ ~a ~}" '(1 2 3))

which produces " 1 2 3 " as output. This formatting capability can be used
to achive
a very simple embedding of html into Lisp.

Let's assume we already have three functions 'table 'tr and 'td. Our html
code to
make a table then might look like

(table :cellpadding 0 :cellspacing 5
  (tr (td "hello") (td "world")))

producing

<table cellpadding="0"
cellspacing="5"><tr><td>hello</td><td>world</td></tr></table>

I assume html tags can be described liked

<tag-name attribute1=value1 ... > content </tag-name>

So function 'table exspects a cons of a property list and the content as
parameters.
With the following helper function 'split-attribs

(defun split-attribs (lst)
  (let (attribs rest key value)
    (loop
      (if (zerop (length lst)) (return))
      (unless (keywordp (car lst)) (return))
      (setf key (string-downcase (pop lst)))
      (setf value (pop lst))
      (if value
        (push (format nil " ~a=\"~a\"" key value) attribs)
        (push (format nil " ~a" key) attribs)))
    (values (reverse attribs) lst)))

the function 'table could be

(defun table (&rest text)
  (multiple-value-bind (attribs rest)
      (split-attribs text)
    (format nil "<table~{~a~}>~{~a~}</table>~%" attribs rest)))

Now let's go one step ahead. For each html tag there has to be such a
function
definition. With the following macro we might generate these functions

(defun tag-format-string (tag)
  (concatenate 'string "<" tag "~{~a~}>~{~a~}</" tag ">~%"))

(defmacro deftag (name)
  (let ((f (tag-format-string (string-downcase (symbol-name name)))))
    `(defun ,name (&rest text)
       (multiple-value-bind (attribs rest)
           (split-attribs text)
         (format nil ,f attribs rest)))))

Thus defining our three functions 'table 'tr and 'td would reduce to

(deftag table)
(deftag tr)
(deftag td)

So the whole html thing can be reduced to approx. 60 lines of code, if we
consider
each 'deftag a line :-)

When talking about html I must mention Kevin Rosenberg's LML package at
http://lml.b9.com

I am interested in your criticism to my approach. With some slight
extensions (short tags
i.e. <br> ((no closing tag </br>)) and LF suppression) I use it to generate
html pages from Lisp.

Andreas

From: Rob Warnock
Subject: Re: easily embedding html into Lisp
Date: 
Message-ID: <LLOdnWvyQN3euNXcRVn-jA@speakeasy.net>
Andreas Thiele <··········@nospam.com> wrote:
+---------------
| I'd like to introduce a simple approach of embedding html into Lisp.
+---------------

You should look at <http://www.cliki.net/Lisp%20Markup%20Languages>,
which lists several readily-available packages which already do
this (or similar). I tend to use HTOUT, but CL-WHO is also nice.
Also see <http://www.cliki.net/HTML-from-sexpr>.

+---------------
| Let's assume we already have three functions 'table 'tr and 'td.
| Our html code to make a table then might look like
|   (table :cellpadding 0 :cellspacing 5
|     (tr (td "hello") (td "world")))
| producing
|   <table cellpadding="0"
|   cellspacing="5"><tr><td>hello</td><td>world</td></tr></table>
+---------------

In HTOUT, that would be written this way.

    (with-html-output (s stream)
      ((:table :cellpadding 0 :cellspacing 5)
	(:tr (:td "hello") (:td "world"))))

and generates:

    <TABLE CELLPADDING='0' CELLSPACING='5'><TR><TD>hello</TD><TD>world</TD></TR></TABLE>

+---------------
| I assume html tags can be described liked
| <tag-name attribute1=value1 ... > content </tag-name>
+---------------

HTOUT uses keywords for tags, so you don't need to define functions
for all of them. Or, if the first element of a form is itself a list
the CAR of which is a keyword, then the CAAR is taken as the tag and
the CDAR is a property list of "attribute value..." (as shown in the
example above).

+---------------
| Now let's go one step ahead. For each html tag there has to be such a
| function definition.
+---------------

Packages such as HTOUT & CL-WHO don't require this, using symbols in
the keyword package as tag markers instead. Any list whose CAR is not
a keyword or whose CAR is not a list starting with a keyword is taken
to be pure Lisp code, which is simply passed through to the compiler.
Also, inside a WITH-HTML-OUTPUT, macrolets are automatically defined
for several common operations, including going back into HTML mode
from Lisp code [note the use of HTM in the following example].

[There is an alternate syntax available which puts the attributes
in a required list after the tag, but I won't go into that here.]

For example, instead of just saying "hello" and "world", suppose you
wanted to write a function that took an entire list of lists, and gave
you an HTML table row per element, with a data item per sub-element.
Furthermore, suppose you want the first element to be the column-head
labels (that is, use <TH> instead of <TD> on the first row). Here's
one version [the LFD calls produce newlines in the HTML, only needed
for human readability]:

    (defun list-html-table (lists &key (stream *standard-output*))
      (let ((column-names (car lists))
	    (rows (cdr lists)))
	(with-html-output (s stream)
	  (:h3 (fmt "Results: ~d rows" (length rows)))
	  (lfd)
	  ((:table :border 1 :cellspacing 0 :cellpadding 1) ; make compact
	    (:tr (lfd)
	      (loop for name in column-names do
		(htm ((:th :nowrap) name) (lfd))))
	    (loop for row in rows do
	      (htm (:tr (lfd)
		     (loop for v in row do
		       (let ((vv (if (or (null v) (string-equal v ""))
				   "&nbsp;"
				   (escape-string v))))
			 (htm ((:td :nowrap) vv) (lfd))))))))
	  (lfd))))

So this call:

    (list-html-table
      '(("Name" "Room" "Phone")
	("Joe" "37A" "2345")
	("Bill" "37B" "5432")
	("Sally" "22C" "1234")))

outputs this:

    <H3>Results: 3 rows</H3>
    <TABLE BORDER='1' CELLSPACING='0' CELLPADDING='1'><TR>
    <TH NOWRAP>Name</TH>
    <TH NOWRAP>Room</TH>
    <TH NOWRAP>Phone</TH>
    </TR><TR>
    <TD NOWRAP>Joe</TD>
    <TD NOWRAP>37A</TD>
    <TD NOWRAP>2345</TD>
    </TR><TR>
    <TD NOWRAP>Bill</TD>
    <TD NOWRAP>37B</TD>
    <TD NOWRAP>5432</TD>
    </TR><TR>
    <TD NOWRAP>Sally</TD>
    <TD NOWRAP>22C</TD>
    <TD NOWRAP>1234</TD>
    </TR></TABLE>

+---------------
| When talking about html I must mention Kevin Rosenberg's LML package
| at http://lml.b9.com
+---------------

That one is also listed on the above-mentioned CLiki pages, as well as
his LML2 (for generating XHTML documents).

+---------------
| I am interested in your criticism to my approach.
+---------------

It certainly works. I used something very similar to it [in Scheme]...
before I found HTOUT.  ;-}


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Pascal Bourguignon
Subject: Re: easily embedding html into Lisp
Date: 
Message-ID: <87hdpzzr1k.fsf@thalassa.informatimago.com>
····@rpw3.org (Rob Warnock) writes:

> Andreas Thiele <··········@nospam.com> wrote:
> +---------------
> | I'd like to introduce a simple approach of embedding html into Lisp.
> +---------------
> 
> You should look at <http://www.cliki.net/Lisp%20Markup%20Languages>,
> which lists several readily-available packages which already do
> this (or similar). I tend to use HTOUT, but CL-WHO is also nice.
> Also see <http://www.cliki.net/HTML-from-sexpr>.
> 
> +---------------
> | Let's assume we already have three functions 'table 'tr and 'td.
> | Our html code to make a table then might look like
> |   (table :cellpadding 0 :cellspacing 5
> |     (tr (td "hello") (td "world")))
> | producing
> |   <table cellpadding="0"
> |   cellspacing="5"><tr><td>hello</td><td>world</td></tr></table>
> +---------------
> 
> In HTOUT, that would be written this way.
> 
>     (with-html-output (s stream)
>       ((:table :cellpadding 0 :cellspacing 5)
> 	(:tr (:td "hello") (:td "world"))))
> [...]
> +---------------
> | I assume html tags can be described liked
> | <tag-name attribute1=value1 ... > content </tag-name>
> +---------------
> 
> HTOUT uses keywords for tags, so you don't need to define functions
> for all of them. Or, if the first element of a form is itself a list
> the CAR of which is a keyword, then the CAAR is taken as the tag and
> the CDAR is a property list of "attribute value..." (as shown in the
> example above).
> 
> +---------------
> | Now let's go one step ahead. For each html tag there has to be such a
> | function definition.
> +---------------
> 
> Packages such as HTOUT & CL-WHO don't require this, using symbols in
> the keyword package as tag markers instead. Any list whose CAR is not
> a keyword or whose CAR is not a list starting with a keyword is taken
> to be pure Lisp code, which is simply passed through to the compiler.
> Also, inside a WITH-HTML-OUTPUT, macrolets are automatically defined
> for several common operations, including going back into HTML mode
> from Lisp code [note the use of HTM in the following example].

 
> [...]
>     (defun list-html-table (lists &key (stream *standard-output*))
>       (let ((column-names (car lists))
> 	    (rows (cdr lists)))
> 	(with-html-output (s stream)
> 	  (:h3 (fmt "Results: ~d rows" (length rows)))
> 	  (lfd)
> 	  ((:table :border 1 :cellspacing 0 :cellpadding 1) ; make compact
> 	    (:tr (lfd)
> 	      (loop for name in column-names do
> 		(htm ((:th :nowrap) name) (lfd))))
> 	    (loop for row in rows do
> 	      (htm (:tr (lfd)
> 		     (loop for v in row do
> 		       (let ((vv (if (or (null v) (string-equal v ""))
> 				   "&nbsp;"
> 				   (escape-string v))))
> 			 (htm ((:td :nowrap) vv) (lfd))))))))
> 	  (lfd))))
> [...]
> +---------------
> | When talking about html I must mention Kevin Rosenberg's LML package
> | at http://lml.b9.com
> +---------------
> 
> That one is also listed on the above-mentioned CLiki pages, as well as
> his LML2 (for generating XHTML documents).
> 
> +---------------
> | I am interested in your criticism to my approach.
> +---------------
> 
> It certainly works. I used something very similar to it [in Scheme]...
> before I found HTOUT.  ;-}

My own variation is as follow.

I translated the DTD of HTML 4.01 as:

(DEFELEMENT A          ()  "anchor")
(DEFELEMENT ABBR       ()  "abbreviated form (e.g., WWW, HTTP, etc.)")
(DEFELEMENT ACRONYM    ())
(DEFELEMENT ADDRESS    ()                        "information on author")
(DEFELEMENT APPLET     (:DEPRECATED :LOOSE-DTD)  "Java applet")
(DEFELEMENT AREA       (:END-FORBIDDEN :EMPTY)   "client-side image map area")
(DEFELEMENT B          ()                        "bold text style")
(DEFELEMENT BASE       (:END-FORBIDDEN :EMPTY)   "document base URI")
;; ...

(DEFATTRIBUTE ABBR 
  (TD TH)
  (%TEXT)  :IMPLIED
  ()  "abbreviation for header cell"
  );;ABBR

(DEFATTRIBUTE ACCEPT-CHARSET
  (FORM)
  (%CHARSETS)  :IMPLIED
  ()  "list of supported charsets"
  );;ACCEPT-CHARSET

(DEFATTRIBUTE ACCEPT 
  (FORM INPUT)
  (%CONTENTTYPES)  :IMPLIED
  ()  "list of MIME types for file upload"
  );;ACCEPT
;; ...


Then I define DEFELEMENT and DEFATTRIBUTE as macros doing what I need
in various cases. I've got a package that define them to generate HTML
as Andreas  (attribute validation is not implemented yet, DEFELEMENT
generates a macro named for the tag instead of a function as in
Andreas' solution. (There's only one shadow: MAP, between HTML4.01
tags and COMMON-LISP).  The advantage of using macros for tags is that
you can embed a lisp body non functionally:

    (table (:width "80%")
       (dolist (row rows)
          (when (odd (length row))
            (tr () 
              (dolist (item row)
                 (td () (p () (insert-pcdata "Item: ~A" item))))))))
    
In HTOUT it would be written almost the same.


Andreas would have to evaluate all arguments and build lists:

   (table :cellpadding 0 :cellspacing 5
     (mapcan (lambda (row) 
               (when (odd (length row))
                 (list (tr (mapcan (lambda (item)
                                    (list (td item))) row))))) rows))


In another package, I defined DEFELEMENT and DEFATTRIBUTE otherwise to
generate an HTML parser.  Since the knowledge of the tags and
attribute is embedded inside WITH-HTML-OUTPUT, I feel it's a solution
that's less declarative, ie. lower level than mine and less useful.�

Also, since HTOUT binds locally an output stream, and doesn't take it
as argument to the non function keyword tags, I don't see how you
could split the description of a page over serveral functions. On the
other hand, for now I have to use a global context to generate HTML,
but this allow be to define methods to insert items on pages such as
headers, feets, forms, etc.  This could be easily done with Andreas'
solution.  Would HTM work outside of the lexical context of
WITH-HTML-OUTPUT?


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

Our enemies are innovative and resourceful, and so are we. They never
stop thinking about new ways to harm our country and our people, and
neither do we.
From: Christophe Turle
Subject: Re: easily embedding html into Lisp
Date: 
Message-ID: <ci9ivn$mg3$1@amma.irisa.fr>
Pascal Bourguignon wrote:
> ····@rpw3.org (Rob Warnock) writes:
> 
> 
>>Andreas Thiele <··········@nospam.com> wrote:
>>+---------------
>>| I'd like to introduce a simple approach of embedding html into Lisp.
>>+---------------
>>
>>You should look at <http://www.cliki.net/Lisp%20Markup%20Languages>,
>>which lists several readily-available packages which already do
>>this (or similar). I tend to use HTOUT, but CL-WHO is also nice.
>>Also see <http://www.cliki.net/HTML-from-sexpr>.
>>
>>+---------------
>>| Let's assume we already have three functions 'table 'tr and 'td.
>>| Our html code to make a table then might look like
>>|   (table :cellpadding 0 :cellspacing 5
>>|     (tr (td "hello") (td "world")))
>>| producing
>>|   <table cellpadding="0"
>>|   cellspacing="5"><tr><td>hello</td><td>world</td></tr></table>
>>+---------------
>>
>>In HTOUT, that would be written this way.
>>
>>    (with-html-output (s stream)
>>      ((:table :cellpadding 0 :cellspacing 5)
>>	  (:tr (:td "hello") (:td "world"))))
>>[...]
>>+---------------
>>| I assume html tags can be described liked
>>| <tag-name attribute1=value1 ... > content </tag-name>
>>+---------------
>>
>>HTOUT uses keywords for tags, so you don't need to define functions
>>for all of them. Or, if the first element of a form is itself a list
>>the CAR of which is a keyword, then the CAAR is taken as the tag and
>>the CDAR is a property list of "attribute value..." (as shown in the
>>example above).
>>
>>+---------------
>>| Now let's go one step ahead. For each html tag there has to be such a
>>| function definition.
>>+---------------
>>
>>Packages such as HTOUT & CL-WHO don't require this, using symbols in
>>the keyword package as tag markers instead. Any list whose CAR is not
>>a keyword or whose CAR is not a list starting with a keyword is taken
>>to be pure Lisp code, which is simply passed through to the compiler.
>>Also, inside a WITH-HTML-OUTPUT, macrolets are automatically defined
>>for several common operations, including going back into HTML mode
>>from Lisp code [note the use of HTM in the following example].
> 
> 
>  
> 
>>[...]
>>    (defun list-html-table (lists &key (stream *standard-output*))
>>      (let ((column-names (car lists))
>>	    (rows (cdr lists)))
>>	(with-html-output (s stream)
>>	  (:h3 (fmt "Results: ~d rows" (length rows)))
>>	  (lfd)
>>	  ((:table :border 1 :cellspacing 0 :cellpadding 1) ; make compact
>>	    (:tr (lfd)
>>	      (loop for name in column-names do
>>		(htm ((:th :nowrap) name) (lfd))))
>>	    (loop for row in rows do
>>	      (htm (:tr (lfd)
>>		     (loop for v in row do
>>		       (let ((vv (if (or (null v) (string-equal v ""))
>>				   "&nbsp;"
>>				   (escape-string v))))
>>			 (htm ((:td :nowrap) vv) (lfd))))))))
>>	  (lfd))))
>>[...]
>>+---------------
>>| When talking about html I must mention Kevin Rosenberg's LML package
>>| at http://lml.b9.com
>>+---------------
>>
>>That one is also listed on the above-mentioned CLiki pages, as well as
>>his LML2 (for generating XHTML documents).
>>
>>+---------------
>>| I am interested in your criticism to my approach.
>>+---------------
>>
>>It certainly works. I used something very similar to it [in Scheme]...
>>before I found HTOUT.  ;-}
> 
> 
> My own variation is as follow.
> 
> I translated the DTD of HTML 4.01 as:
> 
> (DEFELEMENT A          ()  "anchor")
> (DEFELEMENT ABBR       ()  "abbreviated form (e.g., WWW, HTTP, etc.)")
> (DEFELEMENT ACRONYM    ())
> (DEFELEMENT ADDRESS    ()                        "information on author")
> (DEFELEMENT APPLET     (:DEPRECATED :LOOSE-DTD)  "Java applet")
> (DEFELEMENT AREA       (:END-FORBIDDEN :EMPTY)   "client-side image map area")
> (DEFELEMENT B          ()                        "bold text style")
> (DEFELEMENT BASE       (:END-FORBIDDEN :EMPTY)   "document base URI")
> ;; ...
> 
> (DEFATTRIBUTE ABBR 
>   (TD TH)
>   (%TEXT)  :IMPLIED
>   ()  "abbreviation for header cell"
>   );;ABBR
> 
> (DEFATTRIBUTE ACCEPT-CHARSET
>   (FORM)
>   (%CHARSETS)  :IMPLIED
>   ()  "list of supported charsets"
>   );;ACCEPT-CHARSET
> 
> (DEFATTRIBUTE ACCEPT 
>   (FORM INPUT)
>   (%CONTENTTYPES)  :IMPLIED
>   ()  "list of MIME types for file upload"
>   );;ACCEPT
> ;; ...
> 
> 
> Then I define DEFELEMENT and DEFATTRIBUTE as macros doing what I need
> in various cases. I've got a package that define them to generate HTML
> as Andreas  (attribute validation is not implemented yet, DEFELEMENT
> generates a macro named for the tag instead of a function as in
> Andreas' solution. (There's only one shadow: MAP, between HTML4.01
> tags and COMMON-LISP).  The advantage of using macros for tags is that
> you can embed a lisp body non functionally:
> 
>     (table (:width "80%")
>        (dolist (row rows)
>           (when (odd (length row))
>             (tr () 
>               (dolist (item row)
>                  (td () (p () (insert-pcdata "Item: ~A" item))))))))
>     
> In HTOUT it would be written almost the same.
> 
> 
> Andreas would have to evaluate all arguments and build lists:
> 
>    (table :cellpadding 0 :cellspacing 5
>      (mapcan (lambda (row) 
>                (when (odd (length row))
>                  (list (tr (mapcan (lambda (item)
>                                     (list (td item))) row))))) rows))
> 
> 
> In another package, I defined DEFELEMENT and DEFATTRIBUTE otherwise to
> generate an HTML parser.


I'm actually doing the same sort of things about java. The difference with you is that i have defined the DEFs only once. Just 
to parse the java-description. It returns a tree of structures (like DOM). I'm currently writting the pretty-printing of this tree to generate java syntax code. So if someone wants to pretty-print it differently, he doesn't need to know about the initial syntax, he just have to define his dispatch table. He may also do other things like counting the number of methods ...

(defdeclaration import (identifiers :0-*))

(setq *a* (import p1 p2 *))
=>
#<import-declaration identifiers (p1 p2 *)>

;;; you can change for your taste
(set-pprint-dispatch import-declaration
  ... )

(sava-print *a* *standard-io*)
=>
import p1.p2.*



Christophe Turle.
From: Rob Warnock
Subject: Re: easily embedding html into Lisp
Date: 
Message-ID: <1NqdnV4opIrK-dTcRVn-jg@speakeasy.net>
Pascal Bourguignon  <····@mouse-potato.com> wrote:
+---------------
| ····@rpw3.org (Rob Warnock) writes:
| > You should look at <http://www.cliki.net/Lisp%20Markup%20Languages>,
| > which lists several readily-available packages which already do
| > this (or similar). I tend to use HTOUT, but CL-WHO is also nice.
| > Also see <http://www.cliki.net/HTML-from-sexpr>.
...
| > (defun list-html-table (lists &key (stream *standard-output*))
| >   (let ((column-names (car lists))
| >         (rows (cdr lists)))
| > 	(with-html-output (s stream)
| > 	  (:h3 (fmt "Results: ~d rows" (length rows)))
| > 	  (lfd)
| > 	  ((:table :border 1 :cellspacing 0 :cellpadding 1) ; make compact
| > 	    (:tr (lfd)
| > 	      (loop for name in column-names do
| > 		(htm ((:th :nowrap) name) (lfd))))
| > 	    (loop for row in rows do
| > 	      (htm (:tr (lfd)
| > 		     (loop for v in row do
| > 		       (let ((vv (if (or (null v) (string-equal v ""))
| > 				   "&nbsp;"
| > 				   (escape-string v))))
| > 			 (htm ((:td :nowrap) vv) (lfd))))))))
| > 	  (lfd))))
...
| Also, since HTOUT binds locally an output stream, and doesn't take it
| as argument to the non function keyword tags, I don't see how you
| could split the description of a page over serveral functions. On the
| other hand, for now I have to use a global context to generate HTML,
| but this allow be to define methods to insert items on pages such as
| headers, feets, forms, etc.  This could be easily done with Andreas'
| solution.  Would HTM work outside of the lexical context of
| WITH-HTML-OUTPUT?
+---------------

The answer to the latter question is "no", but why does that matter?
You can easily "split the description of a page over several functions"
by simply passing the stream as a parameter to each function and then
opening another WITH-HTML-OUTPUT lexical context in the called function,
exactly as the example LIST-HTML-TABLE function I gave above did.

You can also pass closures to other routines to let them do "callbacks"
to customize their behavior.

E.g., the actual LIST-HTML-TABLE function I use in production is
somewhat more complicated than the above example, in that it allows
you to provide a callback function which is called at various points
in generating the HTML table, so that the callback function can add
extra rows, extra columns, etc. For example, the above LIST-HTML-TABLE
is well-suited to displaying a list of lists which are the results
of an SQL query, but by adding a callback to the invocation, pages
can add "Edit" or "Delete" buttons (say) on each line of the query
results *without* having to copy/mutate the list of list structure.

I also tend to use a lot of "template page" functions which take one
or more closures and wrap standardized decoration (headers, nav bars,
footers, etc.) around the specific page content passed in the closures.

Yes, called functions (including any callbacks you pass) have to do
another WITH-HTML-OUTPUT, but that's just compile-time overhead -- the
run-time overhead is almost zero [one LET].


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Andreas Thiele
Subject: Re: easily embedding html into Lisp
Date: 
Message-ID: <cigqol$b41$04$1@news.t-online.com>
"Pascal Bourguignon" <····@mouse-potato.com> schrieb im Newsbeitrag
···················@thalassa.informatimago.com...
> ····@rpw3.org (Rob Warnock) writes:
>
> > Andreas Thiele <··········@nospam.com> wrote:
> > +---------------
> > | I'd like to introduce a simple approach of embedding html into Lisp.
> > +---------------
> >
> > You should look at <http://www.cliki.net/Lisp%20Markup%20Languages>,
> > which lists several readily-available packages which already do
> > this (or similar). I tend to use HTOUT, but CL-WHO is also nice.
> > Also see <http://www.cliki.net/HTML-from-sexpr>.
> >
> > +---------------
> > | Let's assume we already have three functions 'table 'tr and 'td.
> > | Our html code to make a table then might look like
> > |   (table :cellpadding 0 :cellspacing 5
> > |     (tr (td "hello") (td "world")))
> > | producing
> > |   <table cellpadding="0"
> > |   cellspacing="5"><tr><td>hello</td><td>world</td></tr></table>
> > +---------------
> >
> > In HTOUT, that would be written this way.
> >
> >     (with-html-output (s stream)
> >       ((:table :cellpadding 0 :cellspacing 5)
> > (:tr (:td "hello") (:td "world"))))
> > [...]
> > +---------------
> > | I assume html tags can be described liked
> > | <tag-name attribute1=value1 ... > content </tag-name>
> > +---------------
> >
> > HTOUT uses keywords for tags, so you don't need to define functions
> > for all of them. Or, if the first element of a form is itself a list
> > the CAR of which is a keyword, then the CAAR is taken as the tag and
> > the CDAR is a property list of "attribute value..." (as shown in the
> > example above).
> >
> > +---------------
> > | Now let's go one step ahead. For each html tag there has to be such a
> > | function definition.
> > +---------------
> >
> > Packages such as HTOUT & CL-WHO don't require this, using symbols in
> > the keyword package as tag markers instead. Any list whose CAR is not
> > a keyword or whose CAR is not a list starting with a keyword is taken
> > to be pure Lisp code, which is simply passed through to the compiler.
> > Also, inside a WITH-HTML-OUTPUT, macrolets are automatically defined
> > for several common operations, including going back into HTML mode
> > from Lisp code [note the use of HTM in the following example].
>
>
> > [...]
> >     (defun list-html-table (lists &key (stream *standard-output*))
> >       (let ((column-names (car lists))
> >     (rows (cdr lists)))
> > (with-html-output (s stream)
> >   (:h3 (fmt "Results: ~d rows" (length rows)))
> >   (lfd)
> >   ((:table :border 1 :cellspacing 0 :cellpadding 1) ; make compact
> >     (:tr (lfd)
> >       (loop for name in column-names do
> > (htm ((:th :nowrap) name) (lfd))))
> >     (loop for row in rows do
> >       (htm (:tr (lfd)
> >      (loop for v in row do
> >        (let ((vv (if (or (null v) (string-equal v ""))
> >    "&nbsp;"
> >    (escape-string v))))
> > (htm ((:td :nowrap) vv) (lfd))))))))
> >   (lfd))))
> > [...]
> > +---------------
> > | When talking about html I must mention Kevin Rosenberg's LML package
> > | at http://lml.b9.com
> > +---------------
> >
> > That one is also listed on the above-mentioned CLiki pages, as well as
> > his LML2 (for generating XHTML documents).
> >
> > +---------------
> > | I am interested in your criticism to my approach.
> > +---------------
> >
> > It certainly works. I used something very similar to it [in Scheme]...
> > before I found HTOUT.  ;-}
>
> My own variation is as follow.
>
> I translated the DTD of HTML 4.01 as:
>
> (DEFELEMENT A          ()  "anchor")
> (DEFELEMENT ABBR       ()  "abbreviated form (e.g., WWW, HTTP, etc.)")
> (DEFELEMENT ACRONYM    ())
> (DEFELEMENT ADDRESS    ()                        "information on author")
> (DEFELEMENT APPLET     (:DEPRECATED :LOOSE-DTD)  "Java applet")
> (DEFELEMENT AREA       (:END-FORBIDDEN :EMPTY)   "client-side image map
area")
> (DEFELEMENT B          ()                        "bold text style")
> (DEFELEMENT BASE       (:END-FORBIDDEN :EMPTY)   "document base URI")
> ;; ...
>
> (DEFATTRIBUTE ABBR
>   (TD TH)
>   (%TEXT)  :IMPLIED
>   ()  "abbreviation for header cell"
>   );;ABBR
>
> (DEFATTRIBUTE ACCEPT-CHARSET
>   (FORM)
>   (%CHARSETS)  :IMPLIED
>   ()  "list of supported charsets"
>   );;ACCEPT-CHARSET
>
> (DEFATTRIBUTE ACCEPT
>   (FORM INPUT)
>   (%CONTENTTYPES)  :IMPLIED
>   ()  "list of MIME types for file upload"
>   );;ACCEPT
> ;; ...
>
>
> Then I define DEFELEMENT and DEFATTRIBUTE as macros doing what I need
> in various cases. I've got a package that define them to generate HTML
> as Andreas  (attribute validation is not implemented yet, DEFELEMENT
> generates a macro named for the tag instead of a function as in
> Andreas' solution. (There's only one shadow: MAP, between HTML4.01
> tags and COMMON-LISP).  The advantage of using macros for tags is that
> you can embed a lisp body non functionally:
>
...
>     (table (:width "80%")
>        (dolist (row rows)
>           (when (odd (length row))
>             (tr ()
>               (dolist (item row)
>                  (td () (p () (insert-pcdata "Item: ~A" item))))))))
>
> In HTOUT it would be written almost the same.
>
>
> Andreas would have to evaluate all arguments and build lists:
>
>    (table :cellpadding 0 :cellspacing 5
>      (mapcan (lambda (row)
>                (when (odd (length row))
>                  (list (tr (mapcan (lambda (item)
>                                     (list (td item))) row))))) rows))
> ...

I see. This seems to be the disadvantage of a pure functional approach.
Well, of course, this might be the shortest formulation. Because of
readability I still would use dolist like

(with-output-to-string (s)
  (dolist (item row)
    (format s (td ...

Now I extended the tag functions a little bit, so that they accept a stream
as first parameter:

(defun split-attribs (lst)
  (let* (stream attribs key value)
    (loop
      (if (zerop (length lst)) (return))
      (if (streamp (car lst)) (setf stream (pop lst)))
      (unless (keywordp (car lst)) (return))
      (setf key (string-downcase (pop lst)))
      (setf value (pop lst))
      (if value
        (push (format nil " ~a=\"~a\"" key value) attribs)
        (push (format nil " ~a" key) attribs)))
    (values stream (reverse attribs) lst)))

(defmacro deftag (name)
  (let ((f (tag-format-string (string-downcase (symbol-name name)))))
    `(defun ,name (&rest text)
       (multiple-value-bind (stream attribs rest)
           (split-attribs text)
         (format stream ,f attribs rest)))))

so each dolist will need one with-output-to-string (s) bracket. The whole
thing thus would be

(defun job (rows)
  (table :width "80%"
    (with-output-to-string (s)
      (dolist (row rows)
        (when (oddp (length row))
          (tr s
            (with-output-to-string (s)
              (dolist (item row)
                (td s (p "Item: " item))))))))))

Now the extra lines are unpleasant, but for me this is no real world
problem, because I don't confront each page with data to be processed. I use
a macro which allows easy modification of tables and return the html-code
for the table. So I have this non handy construct only once in my code. The
page would look like

(html
  (body
    ;; create a snapshot-'object' named snapshot and fill it with pascals
rows
    (with-snapshot-table (snapshot) (get-pascals-rows-prepared-for-me ...)
      (setf (column snapshot "ID" :hidden) t) ;; do minor manipulations on
the snapshot
      ;; do other manipulations like adding and modifying columns
      ) ;; on exit return the html code for the table
  ))

So far on this. See my second answer following.

Andreas
From: Joel Ray Holveck
Subject: Re: easily embedding html into Lisp
Date: 
Message-ID: <y7cfz5jmhak.fsf@sindri.juniper.net>
> I'd like to introduce a simple approach of embedding html into Lisp.

What you describe sounds a lot like IMHO.

joelh