From: ········@gmail.com
Subject: macro and cl-who help
Date: 
Message-ID: <544d5793-a22d-49a7-917e-dd74ccba12fe@g31g2000pra.googlegroups.com>
Hello,

 Why this does not work?

(defmacro a-frm ()
 `(:br))

(defun reply ()
 (with-html-output (*standard-output* nil)
   (:html (:body (a-frm)))))

When i run (reply) , I get error : The function :BR is undefined.

Why it does not became (:html (:body (:br)))

Thanks
totu

From: Alessio Stalla
Subject: Re: macro and cl-who help
Date: 
Message-ID: <10f3152b-148a-4478-886e-b1d94dfd2e44@n21g2000vba.googlegroups.com>
On May 12, 4:00 pm, ········@gmail.com wrote:
> Hello,
>
>  Why this does not work?
>
> (defmacro a-frm ()
>  `(:br))
>
> (defun reply ()
>  (with-html-output (*standard-output* nil)
>    (:html (:body (a-frm)))))
>
> When i run (reply) , I get error : The function :BR is undefined.
>
> Why it does not became (:html (:body (:br)))

It's been a while since I've used cl-who, but:
I believe this happens because cl-who uses a limited "code-walker"
that transforms all forms which have keyword as car into html print
statements (sort of). This code walker does not do macroexpansions
(probably because getting macroexpansions right is not that easy to
do). So when it sees (a-frm) it says, no keyword! let's leave it
alone. IIRC if you wrap your macro call in an htm form like this: (htm
(a-frm)) it should do what you want.

hth,
Alessio
From: Rob Warnock
Subject: Re: macro and cl-who help
Date: 
Message-ID: <XfGdnWp2UP9Pv5fXnZ2dnUVZ_vCdnZ2d@speakeasy.net>
Alessio Stalla  <·············@gmail.com> wrote:
+---------------
| ········@gmail.com wrote:
| > Why this does not work?
| >
| > (defmacro a-frm ()
| >   `(:br))
| >
| > (defun reply ()
| >   (with-html-output (*standard-output* nil)
| >      (:html (:body (a-frm)))))
| >
| > When i run (reply) , I get error : The function :BR is undefined.
| > Why it does not became (:html (:body (:br)))
| 
| It's been a while since I've used cl-who, but:
| I believe this happens because cl-who uses a limited "code-walker"
| that transforms all forms which have keyword as car into html print
| statements (sort of). This code walker does not do macroexpansions
| (probably because getting macroexpansions right is not that easy to do).
| So when it sees (a-frm) it says, no keyword! let's leave it alone.
+---------------

All correct so far...

+---------------
| IIRC if you wrap your macro call in an htm form like this:
| (htm (a-frm)) it should do what you want.
+---------------

Unfortunately, that won't work, either! Yes, the appearance of the
(HTM ...) form will force the outer W-H-O to treat the HTM form as
Lisp, but... but... HTM is itself just a macro[1] which just bounces
you back into the "walking forms as HTML data" mode, and so HTM won't
parse the A-FRM, *either*!!

To make this work[2], you have to change your A-FRM macro to include
the HTM inside *it*:

    > (defmacro a-frm ()
	`(htm (:br)))

    A-FRM
    > (defun reply ()
	(with-html-output (*standard-output* nil)
	  (:html
	    (:body (a-frm)))))

    REPLY
    > (reply)
    <HTML><BODY><BR></BODY></HTML>
    > 

It's even messier when the nested thing is a function. In that
case you have to re-open the whole W-H-O context from scratch:

    > (defun a-frm2 ()
	(with-html-output (*standard-output* nil)
	  (:br)))

    A-FRM2
    > (defun reply2 ()
	(with-html-output (*standard-output* nil)
	  (:html
	    (:body (a-frm2)))))

    REPLY2
    > (reply2)
    <HTML><BODY><BR></BODY></HTML>
    > 


-Rob

[1] Strictly speaking, HTM is a MACROLET defined by the outer W-H-O.

[2] Note that the above fixes were actually tested on HTOUT, rather
    than CL-WHO, but AFAIK they *should* work for CL-WHO as well.

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Tamas K Papp
Subject: Re: macro and cl-who help
Date: 
Message-ID: <76up0oF1dp569U1@mid.individual.net>
On Tue, 12 May 2009 20:30:58 -0500, Rob Warnock wrote:

> Alessio Stalla  <·············@gmail.com> wrote: +---------------
> | ········@gmail.com wrote:
> | > Why this does not work?
> | >
> | > (defmacro a-frm ()
> | >   `(:br))
> | >
> | > (defun reply ()
> | >   (with-html-output (*standard-output* nil) | >      (:html (:body
> (a-frm)))))
> | >
> | > When i run (reply) , I get error : The function :BR is undefined. |
> > Why it does not became (:html (:body (:br))) |
> | It's been a while since I've used cl-who, but: | I believe this
> happens because cl-who uses a limited "code-walker" | that transforms
> all forms which have keyword as car into html print | statements (sort
> of). This code walker does not do macroexpansions | (probably because
> getting macroexpansions right is not that easy to do). | So when it sees
> (a-frm) it says, no keyword! let's leave it alone. +---------------
> 
> All correct so far...
> 
> +---------------
> | IIRC if you wrap your macro call in an htm form like this: | (htm
> (a-frm)) it should do what you want. +---------------
> 
> Unfortunately, that won't work, either! Yes, the appearance of the (HTM
> ...) form will force the outer W-H-O to treat the HTM form as Lisp,
> but... but... HTM is itself just a macro[1] which just bounces you back
> into the "walking forms as HTML data" mode, and so HTM won't parse the
> A-FRM, *either*!!
> 
> To make this work[2], you have to change your A-FRM macro to include the
> HTM inside *it*:
> 
>     > (defmacro a-frm ()
> 	`(htm (:br)))
> 
>     A-FRM
>     > (defun reply ()
> 	(with-html-output (*standard-output* nil)
> 	  (:html
> 	    (:body (a-frm)))))
> 
>     REPLY
>     > (reply)
>     <HTML><BODY><BR></BODY></HTML>
>     > 
>     > 
> It's even messier when the nested thing is a function. In that case you
> have to re-open the whole W-H-O context from scratch:
> 
>     > (defun a-frm2 ()
> 	(with-html-output (*standard-output* nil)
> 	  (:br)))
> 
>     A-FRM2
>     > (defun reply2 ()
> 	(with-html-output (*standard-output* nil)
> 	  (:html
> 	    (:body (a-frm2)))))
> 
>     REPLY2
>     > (reply2)
>     <HTML><BODY><BR></BODY></HTML>
>     > 
>     > 
> 
> -Rob
> 
> [1] Strictly speaking, HTM is a MACROLET defined by the outer W-H-O.
> 
> [2] Note that the above fixes were actually tested on HTOUT, rather
>     than CL-WHO, but AFAIK they *should* work for CL-WHO as well.

This is a bit off-topic, but...  I have been using LAML [1] by Kurt
Nørmark for a while to generate HTML.  Things Just Work in LAML,
S-expressions map to HTML, and I can also define functions which just
expand, doing the correct thing.  And it does validation.  It is
written in Scheme.  Does anyone know if there is anything inherent in
CL that would prevent something similar, or it just wasn't done?

Thanks,

Tamas


[1] http://www.cs.aau.dk/~normark/laml/
From: Alessio Stalla
Subject: Re: macro and cl-who help
Date: 
Message-ID: <9300986a-3b66-4c69-a86a-15da1360d73c@e23g2000vbe.googlegroups.com>
On May 13, 4:19 am, Tamas K Papp <······@gmail.com> wrote:
> On Tue, 12 May 2009 20:30:58 -0500, Rob Warnock wrote:
> > Alessio Stalla  <·············@gmail.com> wrote: +---------------
> > | ········@gmail.com wrote:
> > | > Why this does not work?
> > | >
> > | > (defmacro a-frm ()
> > | >   `(:br))
> > | >
> > | > (defun reply ()
> > | >   (with-html-output (*standard-output* nil) | >      (:html (:body
> > (a-frm)))))
> > | >
> > | > When i run (reply) , I get error : The function :BR is undefined. |
> > > Why it does not became (:html (:body (:br))) |
> > | It's been a while since I've used cl-who, but: | I believe this
> > happens because cl-who uses a limited "code-walker" | that transforms
> > all forms which have keyword as car into html print | statements (sort
> > of). This code walker does not do macroexpansions | (probably because
> > getting macroexpansions right is not that easy to do). | So when it sees
> > (a-frm) it says, no keyword! let's leave it alone. +---------------
>
> > All correct so far...
>
> > +---------------
> > | IIRC if you wrap your macro call in an htm form like this: | (htm
> > (a-frm)) it should do what you want. +---------------
>
> > Unfortunately, that won't work, either! Yes, the appearance of the (HTM
> > ...) form will force the outer W-H-O to treat the HTM form as Lisp,
> > but... but... HTM is itself just a macro[1] which just bounces you back
> > into the "walking forms as HTML data" mode, and so HTM won't parse the
> > A-FRM, *either*!!
>
> > To make this work[2], you have to change your A-FRM macro to include the
> > HTM inside *it*:
>
> >     > (defmacro a-frm ()
> >    `(htm (:br)))
>
> >     A-FRM
> >     > (defun reply ()
> >    (with-html-output (*standard-output* nil)
> >      (:html
> >        (:body (a-frm)))))
>
> >     REPLY
> >     > (reply)
> >     <HTML><BODY><BR></BODY></HTML>
>
> > It's even messier when the nested thing is a function. In that case you
> > have to re-open the whole W-H-O context from scratch:
>
> >     > (defun a-frm2 ()
> >    (with-html-output (*standard-output* nil)
> >      (:br)))
>
> >     A-FRM2
> >     > (defun reply2 ()
> >    (with-html-output (*standard-output* nil)
> >      (:html
> >        (:body (a-frm2)))))
>
> >     REPLY2
> >     > (reply2)
> >     <HTML><BODY><BR></BODY></HTML>
>
> > -Rob
>
> > [1] Strictly speaking, HTM is a MACROLET defined by the outer W-H-O.
>
> > [2] Note that the above fixes were actually tested on HTOUT, rather
> >     than CL-WHO, but AFAIK they *should* work for CL-WHO as well.
>
> This is a bit off-topic, but...  I have been using LAML [1] by Kurt
> Nørmark for a while to generate HTML.  Things Just Work in LAML,
> S-expressions map to HTML, and I can also define functions which just
> expand, doing the correct thing.  And it does validation.  It is
> written in Scheme.  Does anyone know if there is anything inherent in
> CL that would prevent something similar, or it just wasn't done?
>
> Thanks,
>
> Tamas
>
> [1]http://www.cs.aau.dk/~normark/laml/

I've given it a quick glance (not tried it though). Pretty impressive,
but if I understood correctly it's meant to be used "offline" to
generate static html files... can it produce html on the fly like cl-
who?

Anyway to answer your question probably the most similar thing in CL
is XMLisp... although it's based on CLOS and not on functions. The AST
is represented as a graph of CLOS objects. There are generic function
you can specialize to control the various steps of serialization/
deserialization to and from XML. It's probably less efficient and less
immediate (no S-expression-based representation, though it's probably
not hard to write one on top of it). On the other hand, it's very
customizable as you can redefine almost any part of it for any class.
Plus, it comes with its reader macros that turn XML documents into
Lisp code building a complex graph of objects!

Bye,
Ale
From: Pascal J. Bourguignon
Subject: Re: macro and cl-who help
Date: 
Message-ID: <7cmy9gay12.fsf@pbourguignon.anevia.com>
Alessio Stalla <·············@gmail.com> writes:

> I've given it a quick glance (not tried it though). Pretty impressive,
> but if I understood correctly it's meant to be used "offline" to
> generate static html files... can it produce html on the fly like cl-
> who?

Well if you have a computer fast enough, I guess you could put on hold
your web server, generate the static html file offline, then resume
the web server to provide the generated data.  If done well, the delay
shouldn't be noticeable.

-- 
__Pascal Bourguignon__
From: Alessio Stalla
Subject: Re: macro and cl-who help
Date: 
Message-ID: <dc84c0fd-2ec0-4692-97cd-be5e555c1fd4@s31g2000vbp.googlegroups.com>
On May 13, 3:30 am, ····@rpw3.org (Rob Warnock) wrote:
> Unfortunately, that won't work, either! Yes, the appearance of the
> (HTM ...) form will force the outer W-H-O to treat the HTM form as
> Lisp, but... but... HTM is itself just a macro[1] which just bounces
> you back into the "walking forms as HTML data" mode, and so HTM won't
> parse the A-FRM, *either*!!
>
> To make this work[2], you have to change your A-FRM macro to include
> the HTM inside *it*:
>
>     > (defmacro a-frm ()
>         `(htm (:br)))
>
>     A-FRM
>     > (defun reply ()
>         (with-html-output (*standard-output* nil)
>           (:html
>             (:body (a-frm)))))
>
>     REPLY
>     > (reply)
>     <HTML><BODY><BR></BODY></HTML>
>     >
>
> It's even messier when the nested thing is a function. In that
> case you have to re-open the whole W-H-O context from scratch:
>
>     > (defun a-frm2 ()
>         (with-html-output (*standard-output* nil)
>           (:br)))
>
>     A-FRM2
>     > (defun reply2 ()
>         (with-html-output (*standard-output* nil)
>           (:html
>             (:body (a-frm2)))))
>
>     REPLY2
>     > (reply2)
>     <HTML><BODY><BR></BODY></HTML>
>     >
>
> -Rob
>
> [1] Strictly speaking, HTM is a MACROLET defined by the outer W-H-O.
>
> [2] Note that the above fixes were actually tested on HTOUT, rather
>     than CL-WHO, but AFAIK they *should* work for CL-WHO as well.
>

Right, my cl-who was dusty :) thanks for pointing it out. I wonder why
it is designed that way... wouldn't it have been more "Lispy" to use
macros for html tags instead of writing a custom "evaluator/compiler"
that just treats keywords differently? E.g.

(html
  (body
    (p (:style "xxx") ".....")))

This would have been extensible with user-defined tags, and would have
avoided htm and friends. But maybe there's a drawback I fail to see...

Alessio
From: gugamilare
Subject: Re: macro and cl-who help
Date: 
Message-ID: <4a801935-4cb6-422b-bf7b-ea60ae5efd13@n21g2000vba.googlegroups.com>
On 13 maio, 17:17, Alessio Stalla <·············@gmail.com> wrote:
>
> Right, my cl-who was dusty :) thanks for pointing it out. I wonder why
> it is designed that way... wouldn't it have been more "Lispy" to use
> macros for html tags instead of writing a custom "evaluator/compiler"
> that just treats keywords differently? E.g.
>
> (html
>   (body
>     (p (:style "xxx") ".....")))
>
> This would have been extensible with user-defined tags, and would have
> avoided htm and friends. But maybe there's a drawback I fail to see...

Yes, there is. This would not work:

(with-html-output (*standard-output* nil)
  (:menu :name "File"
    (:option :name "Print" :shortcut "C-p" :command "print-file")))
>
> Alessio
From: Pascal J. Bourguignon
Subject: Re: macro and cl-who help
Date: 
Message-ID: <873ab8enyg.fsf@galatea.local>
Alessio Stalla <·············@gmail.com> writes:

> On May 13, 3:30�am, ····@rpw3.org (Rob Warnock) wrote:
>> Unfortunately, that won't work, either! Yes, the appearance of the
>> (HTM ...) form will force the outer W-H-O to treat the HTM form as
>> Lisp, but... but... HTM is itself just a macro[1] which just bounces
>> you back into the "walking forms as HTML data" mode, and so HTM won't
>> parse the A-FRM, *either*!!
>>
>> To make this work[2], you have to change your A-FRM macro to include
>> the HTM inside *it*:
>>
>> � � > (defmacro a-frm ()
>> � � � � `(htm (:br)))
>>
>> � � A-FRM
>> � � > (defun reply ()
>> � � � � (with-html-output (*standard-output* nil)
>> � � � � � (:html
>> � � � � � � (:body (a-frm)))))
>>
>> � � REPLY
>> � � > (reply)
>> � � <HTML><BODY><BR></BODY></HTML>
>> � � >
>>
>> It's even messier when the nested thing is a function. In that
>> case you have to re-open the whole W-H-O context from scratch:
>>
>> � � > (defun a-frm2 ()
>> � � � � (with-html-output (*standard-output* nil)
>> � � � � � (:br)))
>>
>> � � A-FRM2
>> � � > (defun reply2 ()
>> � � � � (with-html-output (*standard-output* nil)
>> � � � � � (:html
>> � � � � � � (:body (a-frm2)))))
>>
>> � � REPLY2
>> � � > (reply2)
>> � � <HTML><BODY><BR></BODY></HTML>
>> � � >
>>
>> -Rob
>>
>> [1] Strictly speaking, HTM is a MACROLET defined by the outer W-H-O.
>>
>> [2] Note that the above fixes were actually tested on HTOUT, rather
>> � � than CL-WHO, but AFAIK they *should* work for CL-WHO as well.
>>
>
> Right, my cl-who was dusty :) thanks for pointing it out. I wonder why
> it is designed that way... wouldn't it have been more "Lispy" to use
> macros for html tags instead of writing a custom "evaluator/compiler"
> that just treats keywords differently? E.g.
>
> (html
>   (body
>     (p (:style "xxx") ".....")))
>
> This would have been extensible with user-defined tags, and would have
> avoided htm and friends. But maybe there's a drawback I fail to see...

What I wonder is why you want to use cl-who?


Here are some notes I took before writting my own HTML package.

http://darcs.informatimago.com/public/lisp/common-lisp/html.lisp


------------------------------------------------------------------------

YACLML:

  HTML tags are macros (Leaf tags (without bodies) can be functions:
  deftag vs. deftag-macro.)
  
  (<:tag :attrib value :atrib value ...
      body ...)

  Output to *yaclml-stream*; with-yaclml-stream, with-yaclml-output-to-string



NET.HTML.GENERATOR: (HTMLGEN, ALLEGROSERVE).

  HTML tags are keywords, in the context of the NET.HTML.GENERATOR:HTML macro:

  (html
   (:tag body...)
   ((:tag :attrib value ...) body ....))

  :newline -> inserts a new line in the generated html.
  :princ :princ-safely etc -> to have a run-time value inserted in the html.

  Output to *html-stream*; html-stream 

  Attribute names are not evaluated, attribute values are evaluated.


CL-WHO:

  Similar to NET.HTML.GENERATOR

   (WITH-HTML-OUTPUT
      (htm (:tag :attrib value ... body (str pc-data) body ...)))


HTOUT:

  Similar to NET.HTML.GENERATOR


LML:

  HTML tags are keywords.
  There is a reader macro to insert the PCDATA.

    (p [,(a :href "http://lml.b9.com" "LML") is a Common Lisp package 
       for generating HTML and XHTML documents. LML is authored by 
       ,(a :href ·············@rosenberg.net" "Kevin Rosenberg"). 
       The home page for LML is
       ,(a :href "http://lml.b9.com/" "http://lml.b9.com/").])

  Output to *html-output*.


XHTML:

    #+example-of-use                                                              ;;
    (defun redirect-example (ofile title url)                                     ;;
      (with-xhtml (ostream ofile)                                                 ;;
          (head (title title)                                                     ;;
                (meta :http-equiv "Refresh"                                       ;;
                      :content (format nil "0; URL=~a" url)))                     ;;
          (redirect-example-body ostream title url)))                             ;;
                                                                                  ;;
    #+example-of-use                                                              ;;
    (defun redirect-example-body (ostream title url)                              ;;
      (let ((format-string "This page should automatically redirect you to ~a. ~
                            If it does not, please click on "))                   ;;
        (with-xhtml (ostream)                                                     ;;
          (body (h1 title)                                                        ;;
                (p (format-to-xhtml ostream format-string                         ;;
                                    title)                                        ;;
                   (a :href url "this")                                           ;;
                   " link.")))))                                                  ;;


XML-EMITER:

  There are macros to emit any tag:

    (with-xml-output (*standard-output*)
      (with-tag ("person" '(("age" "19")))
        (with-simple-tag ("firstName")
          (xml-out "Peter"))
        (simple-tag "lastName" "Scott")
        (emit-simple-tags :age 17
                  :school "Iowa State Univeristy"
                  "mixedCaseTag" "Check out the mixed case!"
                  "notShown" nil)))

   

Le Sursis:

    (format t (http-response
               (html
                (head
                 (title "Thank You!"))
                (body
                 (h1 "Thank You!")
                 (img '(("src" . "le-sursis.png")
                        ("alt" . "The Le Sursis banner")))
                 "Thank you for your response."))))

  Tags are functions that return a string containing the generated HTML.
  (O(n�) in space).

------------------------------------------------------------------------

============
HTML IN LISP
============

The various Lisp Markup Languages are designed more from a static
point of view than a dynamic (generation) point of view.  The main
consequence is that there are still two modes, HTML data and Lisp
code, and that some shift operator is needed to go from HTML to Lisp
or from Lisp to HTML (eg. net.html.generator:html & :princ).  Another
difficulty is that the notation is optimized for static attributes.

Usually, tags are macros, because they have bodies that must execute
between the generation of the open tag and the close tag.

In most cases, the HTML is generated on the run, which means that when
an error occurs, invalid HTML is issued if no buffering is explicitely
done.

The main problem with all these schemes is that the attributes must be
symbols or keywords and not expressions to be evaluated, so we cannot
pass a variable list of attributes.

Another problem with these schemes where a root macro walks its body
to transform the keyword HTML tags into lisp is that it needs to be
used again and again in each lexical scope in functions or macros.


Functions have the downside that we cannot pass more than
CALL-ARGUMENTS-LIMIT arguments. So while it would be nice to use
functions for tags, it is not prudent to use &REST to do so.
In anycase care should be taken to avoid O(n�) space as in Le Sursis.




----------------
FUNCTIONAL LAYER
----------------


The main objective of this Lisp Markup is to generate dynamic HTML:
usually we don't have long spans of HTML markup, but on the contrary,
we call a bunch of Lisp functions each generating a few tags or higher
level constructs.

The functions could either return an object representing the tag, or
modify the state of an object representing the document.

Returning an object representing the tag will allow us to write:

      (<:tag* '() (f (<:tag-1*) (<:tag-2*)))
  
and have f select either TAG-1 or TAG-2 to use in the list returned
for TAG.  This is more expressive so our functions will return tag
objects and be thus more functional.


    (<:tag* &optional plist-of-attributes list-of-body-html) --> tag object

    (<:tag*
       (list :attrib value ...)
       (list (<:tag* ...) "pcdata" ...))    

    The attribute value strings are processed and any character
    invalid for the corresponding attribute is escaped (in general
    CDATA).

    The strings in the list-of-body-html are processed and any
    character invalid in PCDATA is escaped.


In general, attributes names are string designators.  When given a
symbol or keyword, the symbol-name is used.  Qualified XML attributes
may be written as string designator containing a colon: 

  (<:html* (list "xmlns" "http://www.w3.org/1999/xhtml"
                 :xml\:lang "en"
                 lang "en")
      ...)

When given as string, case is not changed.  When given as a symbol or
keyword, if the name is all uppercase, then it's downcased, otherwise
it's preserved.


Each function can check the attributes and attribute values, as well
as its contents, and signal an error condition, depending on the DTD
selected.





XHTML rules

  - Elements must be correctly terminated: <p></p>
  - Empty elements must be terminated too: <img />
  - All attribute values must be quoted:   <td rowspan="3"></td>
  - Boolean attributes cannot be minimized: <dl compact="compact"></dl>
  - Tags and attributes must be written in low case.
  - Predefined attribute values must be written in low case: <input type="text" />
  - Hex entities must be written in low case: &x99;
  - name attributes -> id attributes ???
  - use both lang and xml:lang attributes.
  


HTML-STRING (string)                                            Function

  Returns a tag-object that would generate the contents 
  of the STRING as HTML.

  Example:
  
    (HTML-STRING "<P>Some paragraph</P>") --> #<element>



WRITE-HTML (tag-object &optional (stream *html-output*)         Function

   Writes the HTML encoded in the tag-object to the output STREAM.



(write-html 
   (<:html* '()
       (list
         (<:head* '()
            (list (<:title '() '("Some title"))))
         (<:body* (list :style (js:css-inline* :background-color color) "red")
             (list (<:h1 '() '("Title"))
                   (<:p  '() '("Some paragraph text" "and some more")))))))


         
------------
MARKUP LAYER
------------

Another layer will consist of macros which will accept a more lax
syntax for attributes, and build the list of body-html from a body of
lisp code.
 
(<:tag plist-of-attributes &body body)

plist-of-attributes ::= () | - | (:attrib value-expr ...) | lisp-expression .

  If all keys are keywords, 
      then (list ,@plist-of-attributes)
      else plist-of-attributes
  
  (:att (some 'value) (if test :a1 :a2) "value")           ; invalid
  (list :att (some 'value) (if test :a1 :a2) "value")      ; valid



(defmacro tag (attributes &body body)
  `(let ((results))
      (push (tag* ,(if (and (evenp (length attributes))
                         (loop :for (k v) :on attributes
                               :always (keywordp k)))
                    `(list ,@attributes)
                    attributes)
                (let ((*html-tags* '()))
                   (setf results (multiple-value-list (progn ,@body)))
                   (nreverse *html-tags*))) *html-tags*)
      (apply (function values) results)))
  

(table (attributes-for-table)
       (loop for r in rows
          do (tr (loop for c in r do (td c)))))
;; we don't want to use collect here because we want to be able to
;; call TR inside functions called here.


Expands to:


(table (attributes-for-table)
       (loop for r in rows
          do (tr () (loop for c in r do (td () (pcdata c)))))

(push (<:table* '()
        (let ((*html-tags* '()))
            (loop for r in rows
                  do (push (<:tr '()
                              (let ((*html-tags* '()))
                                (loop for c in r 
                                      do (push (<:td '()
                                                 (let ((*html-tags* '()))
                                                   (push (pcdata c))
                                                   (nreverse *html-tags*)))
                                               *html-tags*))
                                (nreverse *html-tags*))) *html-tags*))
           (nreverse *html-tags*))) *html-tags*)


(with-html-output (stream)
  (doctype :loose
    (html ()
       (head ()
          (title () (pcdata "title")))
       (body ()
          (p () (pcdata "para") (pcdata var))))))


(with-html-output (stream)
  (doctype :loose
    (html -
       (head -
          (title - (pcdata "title")))
       (body -
          (p - (pcdata "para") (pcdata var))))))






WITH-HTML-OUTPUT ((&optional stream &key kind encoding) &body body)        Macro
 
   Execute body (collecting *HTML-TAGS*), and finally writes to the STREAM
   the HTML collected.

   KIND indicates which kind of is used: :HTML, :XHTML or :XML.
   (tags may be generated differently in HTML 4.01 than in XHTML 1.0 or XML).

   ENCODING indicates which character encoding is used to write the
   document.  CDATA and PCDATA may be escaped differently depending on
   the encoding.


(defmacro with-html-output ((stream) &body body)
   `(let ((*html-tags* '()))
      (multiple-value-prog1 (progn ,@body)
         (dolist (tag (nreverse *html-tags*))
            (write-html tag stream)))))



Both functions and macros accumulate the generated html bits into the
lists of ELEMENT objects, and don't concatenate any string internally,
until the tree is written to the output stream with WRITE-HTML.  This
means that structure sharing of parts of a document doesn't use any
memory (but a few references).
      
 
========================================================================
EXAMPLES:


With macros, issuing static html; the pcdata must be tagged with the
PCDATA macro:

    (with-html-output ()
      (doctype :loose
               (html -
                     (head -
                           (title - (pcdata "title")))
                     (body (:color "#123456" "background-color" "red")
                           (p - (pcdata "para") (pcdata "var")))))
      (values))

prints:


    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <title>title </title></head>
    <body color="#123456" background-color="red">
    <p>para var </p></body></html>




With functions the lists of attributes and body elements can be built
dynamically.  The strings are automatically converted to pcdata:
 
    (progn
      (write-html (doctype* :loose))
      (write-html
       (html* '()
              (list 
               (head* '()
                      (list (title* '() (list (pcdata* "title")))))
               (body* (list :color "#123456" "background-color" "red")
                      (list (p* '() (list "para" (pcdata "variable"))))))))
      (values))

prints:


    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <title>title </title></head>
    <body color="#123456" background-color="red">
    <p>para variable </p></body></html>


========================================================================

    

-- 
__Pascal Bourguignon__
From: ········@gmail.com
Subject: Re: macro and cl-who help
Date: 
Message-ID: <dc6152d1-6a50-419f-8179-07fcf26e82f1@18g2000prx.googlegroups.com>
On May 14, 1:40 am, ····@informatimago.com (Pascal J. Bourguignon)
wrote:
> Alessio Stalla <·············@gmail.com> writes:
> > On May 13, 3:30 am, ····@rpw3.org (Rob Warnock) wrote:
> >> Unfortunately, that won't work, either! Yes, the appearance of the
> >> (HTM ...) form will force the outer W-H-O to treat the HTM form as
> >> Lisp, but... but... HTM is itself just a macro[1] which just bounces
> >> you back into the "walking forms as HTML data" mode, and so HTM won't
> >> parse the A-FRM, *either*!!
>
> >> To make this work[2], you have to change your A-FRM macro to include
> >> the HTM inside *it*:
>
> >>     > (defmacro a-frm ()
> >>         `(htm (:br)))
>
> >>     A-FRM
> >>     > (defun reply ()
> >>         (with-html-output (*standard-output* nil)
> >>           (:html
> >>             (:body (a-frm)))))
>
> >>     REPLY
> >>     > (reply)
> >>     <HTML><BODY><BR></BODY></HTML>
> >>     >
>
> >> It's even messier when the nested thing is a function. In that
> >> case you have to re-open the whole W-H-O context from scratch:
>
> >>     > (defun a-frm2 ()
> >>         (with-html-output (*standard-output* nil)
> >>           (:br)))
>
> >>     A-FRM2
> >>     > (defun reply2 ()
> >>         (with-html-output (*standard-output* nil)
> >>           (:html
> >>             (:body (a-frm2)))))
>
> >>     REPLY2
> >>     > (reply2)
> >>     <HTML><BODY><BR></BODY></HTML>
> >>     >
>
> >> -Rob
>
> >> [1] Strictly speaking, HTM is a MACROLET defined by the outer W-H-O.
>
> >> [2] Note that the above fixes were actually tested on HTOUT, rather
> >>     than CL-WHO, but AFAIK they *should* work for CL-WHO as well.
>
> > Right, my cl-who was dusty :) thanks for pointing it out. I wonder why
> > it is designed that way... wouldn't it have been more "Lispy" to use
> > macros for html tags instead of writing a custom "evaluator/compiler"
> > that just treats keywords differently? E.g.
>
> > (html
> >   (body
> >     (p (:style "xxx") ".....")))
>
> > This would have been extensible with user-defined tags, and would have
> > avoided htm and friends. But maybe there's a drawback I fail to see...
>
> What I wonder is why you want to use cl-who?
>
> Here are some notes I took before writting my own HTML package.
>
> http://darcs.informatimago.com/public/lisp/common-lisp/html.lisp
>
> ------------------------------------------------------------------------
>
> YACLML:
>
>   HTML tags are macros (Leaf tags (without bodies) can be functions:
>   deftag vs. deftag-macro.)
>
>   (<:tag :attrib value :atrib value ...
>       body ...)
>
>   Output to *yaclml-stream*; with-yaclml-stream, with-yaclml-output-to-string
>
> NET.HTML.GENERATOR: (HTMLGEN, ALLEGROSERVE).
>
>   HTML tags are keywords, in the context of the NET.HTML.GENERATOR:HTML macro:
>
>   (html
>    (:tag body...)
>    ((:tag :attrib value ...) body ....))
>
>   :newline -> inserts a new line in the generated html.
>   :princ :princ-safely etc -> to have a run-time value inserted in the html.
>
>   Output to *html-stream*; html-stream
>
>   Attribute names are not evaluated, attribute values are evaluated.
>
> CL-WHO:
>
>   Similar to NET.HTML.GENERATOR
>
>    (WITH-HTML-OUTPUT
>       (htm (:tag :attrib value ... body (str pc-data) body ...)))
>
> HTOUT:
>
>   Similar to NET.HTML.GENERATOR
>
> LML:
>
>   HTML tags are keywords.
>   There is a reader macro to insert the PCDATA.
>
>     (p [,(a :href "http://lml.b9.com" "LML") is a Common Lisp package
>        for generating HTML and XHTML documents. LML is authored by
>        ,(a :href ·············@rosenberg.net" "Kevin Rosenberg").
>        The home page for LML is
>        ,(a :href "http://lml.b9.com/" "http://lml.b9.com/").])
>
>   Output to *html-output*.
>
> XHTML:
>
>     #+example-of-use                                                              ;;
>     (defun redirect-example (ofile title url)                                     ;;
>       (with-xhtml (ostream ofile)                                                 ;;
>           (head (title title)                                                     ;;
>                 (meta :http-equiv "Refresh"                                       ;;
>                       :content (format nil "0; URL=~a" url)))                     ;;
>           (redirect-example-body ostream title url)))                             ;;
>                                                                                   ;;
>     #+example-of-use                                                              ;;
>     (defun redirect-example-body (ostream title url)                              ;;
>       (let ((format-string "This page should automatically redirect you to ~a. ~
>                             If it does not, please click on "))                   ;;
>         (with-xhtml (ostream)                                                     ;;
>           (body (h1 title)                                                        ;;
>                 (p (format-to-xhtml ostream format-string                         ;;
>                                     title)                                        ;;
>                    (a :href url "this")                                           ;;
>                    " link.")))))                                                  ;;
>
> XML-EMITER:
>
>   There are macros to emit any tag:
>
>     (with-xml-output (*standard-output*)
>       (with-tag ("person" '(("age" "19")))
>         (with-simple-tag ("firstName")
>           (xml-out "Peter"))
>         (simple-tag "lastName" "Scott")
>         (emit-simple-tags :age 17
>                   :school "Iowa State Univeristy"
>                   "mixedCaseTag" "Check out the mixed case!"
>                   "notShown" nil)))
>
> Le Sursis:
>
>     (format t (http-response
>                (html
>                 (head
>                  (title "Thank You!"))
>                 (body
>                  (h1 "Thank You!")
>                  (img '(("src" . "le-sursis.png")
>                         ("alt" . "The Le Sursis banner")))
>                  "Thank you for your response."))))
>
>   Tags are functions that return a string containing the generated HTML.
>   (O(n²) in space).
>
> ------------------------------------------------------------------------
>
> ============
> HTML IN LISP
> ============
>
> The various Lisp Markup Languages are designed more from a static
> point of view than a dynamic (generation) point of view.  The main
> consequence is that there are still two modes, HTML data and Lisp
> code, and that some shift operator is needed to go from HTML to Lisp
> or from Lisp to HTML (eg. net.html.generator:html & :princ).  Another
> difficulty is that the notation is optimized for static attributes.
>
> Usually, tags are macros, because they have bodies that must execute
> between the generation of the open tag and the close tag.
>
> In most cases, the HTML is generated on the run, which means that when
> an error occurs, invalid HTML is issued if no buffering is explicitely
> done.
>
> The main problem with all these schemes is that the attributes must be
> symbols or keywords and not expressions to be evaluated, so we cannot
> pass a variable list of attributes.
>
> Another problem with these schemes where a root macro walks its body
> to transform the keyword HTML tags into lisp is that it needs to be
> used again and again in each lexical scope in functions or macros.
>
> Functions have the downside that we cannot pass more than
> CALL-ARGUMENTS-LIMIT arguments. So while it would be nice to use
> functions for tags, it is not prudent to use &REST to do so.
> In anycase care should be taken to avoid O(n²) space as in Le Sursis.
>
> ----------------
> FUNCTIONAL LAYER
> ----------------
>
> The main objective of this Lisp Markup is to generate dynamic HTML:
> usually we don't have long spans of HTML markup, but on the contrary,
> we call a bunch of Lisp functions each generating a few tags or higher
> level constructs.
>
> The functions could either return an object representing the tag, or
> modify the state of an object representing the document.
>
> Returning an object representing the tag will allow us to write:
>
>       (<:tag* '() (f (<:tag-1*) (<:tag-2*)))
>
> and have f select either TAG-1 or TAG-2 to use in the list returned
> for TAG.  This is more expressive so our functions will return tag
> objects and be thus more functional.
>
>     (<:tag* &optional plist-of-attributes list-of-body-html) --> tag object
>
>     (<:tag*
>        (list :attrib value ...)
>        (list (<:tag* ...) "pcdata" ...))    
>
>     The attribute value strings are processed and any character
>     invalid for the corresponding attribute is escaped (in general
>     CDATA).
>
>     The strings in the list-of-body-html are processed and any
>     character invalid in PCDATA is escaped.
>
> In general, attributes names are string designators.  When given a
> symbol or keyword, the symbol-name is used.  Qualified XML attributes
> may be written as string designator containing a colon:
>
>   (<:html* (list "xmlns" "http://www.w3.org/1999/xhtml"
>                  :xml\:lang "en"
>                  lang "en")
>       ...)
>
> When given as string, case is not changed.  When given as a symbol or
> keyword, if the name is all uppercase, then it's downcased, otherwise
> it's preserved.
>
> Each function can check the attributes and attribute values, as well
> as its contents, and signal an error condition, depending on the DTD
> selected.
>
> XHTML rules
>
>   - Elements must be correctly terminated: <p></p>
>   - Empty elements must be terminated too: <img />
>   - All attribute values must be quoted:   <td rowspan="3"></td>
>   - Boolean attributes cannot be minimized: <dl compact="compact"></dl>
>   - Tags and attributes must be written in low case.
>   - Predefined attribute values must be written in low case: <input type="text" />
>   - Hex entities must be written in low case: &x99;
>   - name attributes -> id attributes ???
>   - use both lang and xml:lang attributes.
>
> HTML-STRING (string)                                            Function
>
>   Returns a tag-object that would generate the contents
>   of the STRING as HTML.
>
>   Example:
>
>     (HTML-STRING "<P>Some paragraph</P>") --> #<element>
>
> WRITE-HTML (tag-object &optional (stream *html-output*)        
> ...
>
> read more »

Thanks for links , I did checked out htmlgen package ,it works just
fine
with macros and is simple as cl-who.
From: Rob Warnock
Subject: Re: macro and cl-who help
Date: 
Message-ID: <6LKdnaSCBaDVapbXnZ2dnUVZ_qGdnZ2d@speakeasy.net>
Alessio Stalla  <·············@gmail.com> wrote:
+---------------
| Right, my cl-who was dusty :) thanks for pointing it out. I wonder why
| it is designed that way... wouldn't it have been more "Lispy" to use
| macros for html tags instead of writing a custom "evaluator/compiler"
| that just treats keywords differently? E.g.
| 
| (html
|   (body
|     (p (:style "xxx") ".....")))
| 
| This would have been extensible with user-defined tags, and would have
| avoided htm and friends. But maybe there's a drawback I fail to see...
+---------------

You can do as you suggest (I believe HTMLGEN does, in fact),
but then you have to worry about namespace collisions between
HTML tags and your macros/functions. You [or your HTML-generating
library] also have to explicitly predefine a macro for every
possible HTML tag you might ever want to emit.

Whereas although HTOUT & CL-WHO do require you to "switch namespaces"
semi-manually with HTM, there's no collision between HTML tags and your
macros/functions, since one normally never defines a macro or function
in the keyword package. Yes, it's a hack, but a convenient one.


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Zach Beane
Subject: Re: macro and cl-who help
Date: 
Message-ID: <m3fxfal7zj.fsf@unnamed.xach.com>
········@gmail.com writes:

> Hello,
>
>  Why this does not work?
>
> (defmacro a-frm ()
>  `(:br))
>
> (defun reply ()
>  (with-html-output (*standard-output* nil)
>    (:html (:body (a-frm)))))
>
> When i run (reply) , I get error : The function :BR is undefined.
>
> Why it does not became (:html (:body (:br)))

The rules followed in a WITH-HTML-OUTPUT body are not the same as the
evaluation rules for normal Lisp code.

CL-WHO's rules are described here:

  http://weitz.de/cl-who/#syntax

In this case, you're seeing the rule that starts "A form which is
neither a string nor a keyword nor a list beginning with a keyword will
be left as is..."

Zach
From: Pascal J. Bourguignon
Subject: Re: macro and cl-who help
Date: 
Message-ID: <7c3abacrkf.fsf@pbourguignon.anevia.com>
········@gmail.com writes:

> Hello,
>
>  Why this does not work?
>
> (defmacro a-frm ()
>  `(:br))
>
> (defun reply ()
>  (with-html-output (*standard-output* nil)
>    (:html (:body (a-frm)))))
>
> When i run (reply) , I get error : The function :BR is undefined.
>
> Why it does not became (:html (:body (:br)))

Have a look at:
http://lisp-univ-etc.blogspot.com/2009/03/cl-who-macros.html

-- 
__Pascal Bourguignon__