From: Jason S. Cornez
Subject: lisp html generation
Date: 
Message-ID: <m1lk7uyvte7.fsf@au-bon-pain.lcs.mit.edu>
Lispers,

I've looked at several CL HTML generation tools, but none of them seem
quite right to me.  I've at least briefly investigated all the ones
listed on cliki, and especially the AllegroServe HTMLgen facility.
All of these seem to work well at what they do, but somehow miss the
mark of what I might expect.  I am considering writing my own html
generation library, but I thought I'd ask here first what people are
using and how it meets their needs.

What I might like is something along these lines:
[assuming use of an html package...]

(html
 (head
  (title "My title"))
 (body :bgcolor "ffffff"
  (table :border 1
   (tr (td "first")(td "second"))
   (tr (td "third")(td "fourth")))))

When evaluated, one gets:

<html>
<head>
<title>My title</title>
</head>
<body bgcolor="ffffff">
<table border="1">
  <tr>
    <td>first</td><td>second</td>
  </tr>
  <tr>
    <td>third</td><td>fourth</td>
  </tr>
</table>
</body>
</html>

There are several libraries that get close enough to this, although
none seem too concerned with the format of the output.

Suppose that now I want to set the font of all table cells to be arial
and their is a requirement to avoid style sheets (I work for a
consulting firm and clients request this all the time).  Oops, we'd
really like futura instead of arial.

What I'd like to be able to do is simply redefine the (td) function
(using defun, defmacro, defmethod or whatever the framework requires) so
that it outputs (in this case):

<td><font face='futura'>first</font></td>

I imagine something like:

(deftag td (attributes body)
  ;; potentially add more attributes to alist or hash
  (tag-open attributes)
  "<font face='futura'>"
  (tag-body body)
  "</font>"
  (tag-close))

Generating html is a big pain and a tool like this could really
help. (Might also be helpful as a tool within emacs.)

Thanks,

-Jason

From: Wade Humeniuk
Subject: Re: lisp html generation
Date: 
Message-ID: <a157ed$f3s$1@news3.cadvision.com>
I wrote my own (primitve-html.lisp), but the "code" does not look like what
you are looking for.  I decided to not utilize automatic end-tag generation
since html can be more spaghetti-ized that simple list forms.  Also
primitive-html looks almost exactly like the generated html, so I am not
hiding what I am doing.  I just prefer it over the other html macros.

(html
 (head
  (title "My title"))
 (body :bgcolor "ffffff"
  (table :border 1
   (tr (td "first")(td "second"))
   (tr (td "third")(td "fourth")))))

would in primitive-html becomes

(let ((*primitive-html-stream* *standard-output*))
(<html>)
(<head>)
(<title>)(prinhtml "My Title")(</title>)
(</head>)
(<body> :bgcolor "ffffff")
(<table> :border 1)
(<tr>)(<td>)(prinhtml "first")(<td>)(prinhtml "second")
(<tr>)(<td>)(prinhtml "third")(<td>(prinhtml "fourth")
(</table>)
(</body>)
(</html>))

>What I'd like to be able to do is simply redefine the (td) function
>(using defun, defmacro, defmethod or whatever the framework requires) so
>that it outputs (in this case):

><td><font face='futura'>first</font></td>

>I imagine something like:

>(deftag td (attributes body)
 > ;; potentially add more attributes to alist or hash
 > (tag-open attributes)
 > "<font face='futura'>"
 > (tag-body body)
 > "</font>"
  >(tag-close))

To extend primitive-html you could write

(defmacro <td-futura> (&rest attributes)
    `(progn (<td> ,@attributes)(<font> :face "futura")))

(defmacro </td-futura> ()
    `(progn (</font>) (</td>)))

or any other macro you may wish.


You are free to use the code (no restrictions, no GPL either), see

http://www.cadvision.com/humeniuw/primitive-html.lisp


There also an example

http://www.cadvision.com/humeniuw/html-report.lisp


Wade
From: Brian P Templeton
Subject: Re: lisp html generation
Date: 
Message-ID: <87zo3szeys.fsf@tunes.org>
"Wade Humeniuk" <········@cadvision.com> writes:

> I wrote my own (primitve-html.lisp), but the "code" does not look like what
> you are looking for.  I decided to not utilize automatic end-tag generation
> since html can be more spaghetti-ized that simple list forms.  Also
> primitive-html looks almost exactly like the generated html, so I am not
> hiding what I am doing.  I just prefer it over the other html macros.
> 
> (html
>  (head
>   (title "My title"))
>  (body :bgcolor "ffffff"
>   (table :border 1
>    (tr (td "first")(td "second"))
>    (tr (td "third")(td "fourth")))))
> 
> would in primitive-html becomes
> 
> (let ((*primitive-html-stream* *standard-output*))
> (<html>)
> (<head>)
> (<title>)(prinhtml "My Title")(</title>)
> (</head>)
> (<body> :bgcolor "ffffff")
> (<table> :border 1)
> (<tr>)(<td>)(prinhtml "first")(<td>)(prinhtml "second")
> (<tr>)(<td>)(prinhtml "third")(<td>(prinhtml "fourth")
> (</table>)
> (</body>)
> (</html>))
> 
>>What I'd like to be able to do is simply redefine the (td) function
>>(using defun, defmacro, defmethod or whatever the framework requires) so
>>that it outputs (in this case):
> 
>><td><font face='futura'>first</font></td>
> 
>>I imagine something like:
> 
>>(deftag td (attributes body)
>  > ;; potentially add more attributes to alist or hash
>  > (tag-open attributes)
>  > "<font face='futura'>"
>  > (tag-body body)
>  > "</font>"
>   >(tag-close))
> 
> To extend primitive-html you could write
> 
> (defmacro <td-futura> (&rest attributes)
>     `(progn (<td> ,@attributes)(<font> :face "futura")))
> 
> (defmacro </td-futura> ()
>     `(progn (</font>) (</td>)))
> 
> or any other macro you may wish.
> 
> 
> You are free to use the code (no restrictions, no GPL either), see
> 
> http://www.cadvision.com/humeniuw/primitive-html.lisp
> 
Is it public domain? It can cause legal problems for users of your
library if you don't specify any license (or that it is public
domain).

> 
> There also an example
> 
> http://www.cadvision.com/humeniuw/html-report.lisp
> 
> 
> Wade
> 
> 
> 
> 
> 

-- 
BPT <···@tunes.org>	    		/"\ ASCII Ribbon Campaign
backronym for Linux:			\ / No HTML or RTF in mail
	Linux Is Not Unix			 X  No MS-Word in mail
Meme plague ;)   --------->		/ \ Respect Open Standards
From: Wade Humeniuk
Subject: Re: lisp html generation
Date: 
Message-ID: <a1b7u2$h88$1@news3.cadvision.com>
> Is it public domain? It can cause legal problems for users of your
> library if you don't specify any license (or that it is public
> domain).

I have already posted it.  It is free of me and I am free of it.  Right at
the top it says "Free for all", may Google be my witness!

Wade
From: Chris Riesbeck
Subject: Re: lisp html generation
Date: 
Message-ID: <riesbeck-01E62B.15285104012002@news.it.nwu.edu>
In article <···············@au-bon-pain.lcs.mit.edu>, 
·····@au-bon-pain.lcs.mit.edu (Jason S. Cornez) wrote:

>I've looked at several CL HTML generation tools, but none of them seem
>quite right to me... What I might like is something along these lines:
>
>(html
> (head
>  (title "My title"))
> (body :bgcolor "ffffff"
>  (table :border 1
>   (tr (td "first")(td "second"))
>   (tr (td "third")(td "fourth")))))

This is very close to Allegro's HTML generator macro and
that's pretty easy to implement. I'd recommend implementing
the Allegro format, and adding your extension.

Allegro uses keywords instead of symbols. No need to export anything
from the HTML generator package except the HTML macro name 
itself.

Also, the HTML macro can assume any keyword in the
appropriate locations is a tag. Tags don't need to be defined
first. Handy if you don't want to bother listing everything 
in HTML. Also nice because you can generate XML at no extra charge.

If you use regular symbols, either you have to export those 
symbols (which may cause name conflicts), or define HTML
to use string equal, not EQL. If you want head, title, ...
to be Lisp macros, then you have to export, and hope
HTML doesn't use any common Lisp names.

Allegro nests element attributes in a list, i.e., 

  ((:body :bgcolor "ffffff")
   ((table :border 1)
    (tr ...

Those parentheses are annoying but they simplify parsing.
Your way is easier to read and write but your code will have
to collect attributes from the beginning of 

  (tag key value key value ...)

and not confuse an attribute value with element contents, e.g., 
not parse

  (option :disabled "choice 1")

as

  <option disabled="choice 1">

when it should be

  <option disabled>choice 1


>Suppose that now I want to set the font of all table cells to be arial
>and their is a requirement to avoid style sheets (I work for a
>consulting firm and clients request this all the time).

My sympathies. How nice of clients to make future maintenance
a pain for all. 

>(using defun, defmacro, defmethod or whatever the framework requires) so
>that it outputs (in this case):
>
><td><font face='futura'>first</font></td>
>
>I imagine something like:
>
>(deftag td (attributes body)
>  ;; potentially add more attributes to alist or hash
>  (tag-open attributes)
>  "<font face='futura'>"
>  (tag-body body)
>  "</font>"
>  (tag-close))

This looks like a nice extension. Since the best way
to implement the Allegro HTML macro is by associating
functions with tags in a table, it shouldn't be hard
to add this. The default function when none is defined
would just print the tag, attributes (if any) and
content (if any).
From: Steven M. Haflich
Subject: Re: lisp html generation
Date: 
Message-ID: <3C361AE3.9D04A86A@pacbell.net>
"Jason S. Cornez" wrote:

> I've looked at several CL HTML generation tools, but none of them seem
> quite right to me.
> ...
> There are several libraries that get close enough to this, although
> none seem too concerned with the format of the output.

I too was unhappy with the Allegroserve htmlhgen so developed one I
prefer over the past year or so.  I've no time to describe it right
now, but the two salient features are that it integrates transparently
with other Lisp code, is not limited to any fixed set of html tags
(since it is actually an xml/xhtml generator), and does pretty
printing if *print-pretty* is true.  Pretty printing is a waste of
compute time and bandwidth in production, but a tremendous help during
development.

This code is probably going to be released under open source before
very long, but if there is a lot of demand I could hurry it...
From: Tim Bradshaw
Subject: Re: lisp html generation
Date: 
Message-ID: <ey3zo3l3s9h.fsf@cley.com>
* Jason S Cornez wrote:

> (html
>  (head
>   (title "My title"))
>  (body :bgcolor "ffffff"
>   (table :border 1
>    (tr (td "first")(td "second"))
>    (tr (td "third")(td "fourth")))))

> When evaluated, one gets:

> <html>
> <head>
> <title>My title</title>
> </head>
> <body bgcolor="ffffff">
> <table border="1">
>   <tr>
>     <td>first</td><td>second</td>
>   </tr>
>   <tr>
>     <td>third</td><td>fourth</td>
>   </tr>
> </table>
> </body>
> </html>

My HTML generation stuff will do more-or-less this, as will many
others. I never worried about the format of the output as I only every
generate HTML as machine language with my system.  

> Suppose that now I want to set the font of all table cells to be arial
> and their is a requirement to avoid style sheets (I work for a
> consulting firm and clients request this all the time).  Oops, we'd
> really like futura instead of arial.

What I think you want here is something slightly cleverer than this.
I have a system which does pretty much this as well, although not
perhaps in the way you want.  What it does is two things:

Firstly define a new source form for markup documents which is
basically HTML-without-the-braindead-syntax.  It looks kind of like
HTML but it's less verbose:

        <html<head<title|my title>>
         <body :bgcolor "red"
          <table ...>>>

Secondly it defines a language for this system, where macros work by
rewriting the parse tree.  The parse tree is just lists, and the
macros are essentially just lisp functions which rewrite these lists
into other lists until there are no macros left.  Finally the aprse
tree is spat out as *ML.  Using this it's quite easy to do all sorts
of useful things.  One of the first things I did was a macro called
TOCIFY which lets you type:

   ... <tocify
         <h1|head...>
         ...
         <h2|...> ...>

and will generate an appropriate table of contents.  You can do pretty
much anything.  The specific case of rewriting x to x with attributes
would need some slight cleverness because you'd want to avoid
recursion, but this could be dealt with easily - I ahven't because I
use style sheets (I'm more interested in being able to do reasonably
large documents in TML than in flashing lights and pretty colours).

The thing that it does not do out of the box is to allow embedding
these documents in code (in the way that my earlier HTML generation
stuff did). That's because it's designed to let me actually write
files with stuff in which get processed, not for on-the-fly
generation.  However it exposes enough mechanism that you could embed
things pretty easily.

It's not publically available yet because I need to write a manual for
the macro stuff, but it's getting reasonably heavy use, and it will
get released at some point under some fairly friendly license.

--tim

(The TML surface syntax is based on an aside by Erik in this group,
although it is, I think, hackier than what he intended).