Subject: Re: Keywords and CL-WHO
From: (Rob Warnock)
Date: Fri, 22 Sep 2006 00:11:24 -0500
Newsgroups: comp.lang.lisp
Message-ID: <>
Dustin Withers <> wrote:
| a wrote:
| > (cl-who:with-html-output (*standard-output* nil :prologue t)
| >    `(,(intern "FOO" :keyword) (:body "test")))
| >
| > <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
| > "">
| > (:FOO (:BODY "test"))
| Ok so that works...

No it doesn't, sorry. "A" confused himself [and you]:

1. The *only* output which went to *STANDARD-OUTPUT* was the prologue.
   None of the FOO stuff went anywhere.

2. WITH-HTML-OUTPUT returns a *value* [which the REPL printed], which
   in the above case happened to be the value of the last form in the
   &BODY arg. The (:FOO (:BODY "test")) value shown above is the result
   of the *evaluation* of the backquoted form, which had no side-effects,
   and in particular was *NOT* output to *STANDARD-OUTPUT*.

The following may make it more clear: First, note that we can replace
the backquoted form by its exact [except for potential sharing of
structure] equivalent expansion:

    > `(,(intern "FOO" :keyword) (:body "test"))

    (:FOO (:BODY "test"))
    > (list (intern "FOO" :keyword) '(:body "test"))

    (:FOO (:BODY "test"))
    > (equal * **)		; See? They're equal.


Now let's put that version into a sexp-based HTML template
and look at the code that WITH-HTML-OUTPUT generates:

    > (macroexpand
       '(cl-who:with-html-output (*standard-output* nil :prologue t)
	      "Some text"
	      (list (intern "FOO" :keyword) '(:body "test"))
	      "Some more text"))))

	"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"\"><html><body>Some text"
       (LIST (INTERN "FOO" :KEYWORD) '(:BODY "test"))
       (WRITE-STRING "Some more text</body></html>" *STANDARD-OUTPUT*)))

See? The LIST form (or the equivalent backquoted form) results in
*only* a value -- the list (:FOO (:BODY "test")) -- which is then
immediately thrown away [since it's not the last such value].
It has no effect on the output:

    > (with-output-to-string (string)
	(cl-who:with-html-output (*standard-output* string :prologue t)
	      "Some text"
	      (list (intern "FOO" :keyword) '(:body "test"))
	      "Some more text"))))

    "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"\"><html><body>Some textSome more text</body></html>"

I again strongly suggest that you consider simply walking your
internal XML document tree yourself, emitting XML (or HTML) text
as needed during the walk. Something like this, but you'd need
to add all the specific details appropriate to your application:

    > (defun walk-and-emit (tree &key (stream *standard-output*))
	  ((null tree)
	  ((and (consp tree) (consp (car tree)))
	   (error "This version can't handle attributes: ~s" tree))
	  ((consp tree)
	   (format stream "<~a>" (car tree))
	   (dolist (i (cdr tree))
	     (walk-and-emit i :stream stream))
	   (format stream "</~a>" (car tree)))
	  (t (format stream "~a" tree))))

    > (with-output-to-string (string)
	(walk-and-emit '(document (type "Purchase Order")
				    (description "Desk")
				    (quantity 1)
				    (unit_cost "$153.24"))
				    (description "Pencil")
				    (quantity 125)
				    (unit_cost "$0.153")))
		       :stream string))



Rob Warnock			<>
627 26th Avenue			<URL:>
San Mateo, CA 94403		(650)572-2607