Hunchentoot/cl-who Page Composition
I'm trying to put together a few pages in hunchentoot as an experiment, and I'm running into an unexpected wall. As an example, I have the following template macro.
(defmacro page-template ((&key title) &body body)
`(with-html-output-to-string
(*standard-output* nil :prologue t :indent t)
(:html :xmlns "http://www.w3.org/1999/xhtml" :xml\:lang "en" :lang "en"
(:head (:meta :http-equiv "Content-Type" :content "text/html;charset=utf-8")
(:title ,(format nil "~@[~A - ~]Test Site" title)))
(:body ,@body))))
Now when I have a pure text page, or one filled with html literals like
(define-easy-handler (test-page :uri "/") () (page-template (:title "Splash Page") (:p "Testing testing")))
everything is a-ok. The page outputs properly and I can see te efforts of my code instantly. However, when I have a page which is made up of redundant elements, it's not as simple. For example, lets say I have a page on which for whatever reason I want to display three RSS newsfeeds. This is a sufficiently complex component that I want to abstract it out, so to my minnd, I should be able to do something like
(define-easy-handler (test-feed :uri "/feeds") ()
(page-template (:title "Splash Page")
(publish-newsfeed "http://nf-one.html")
(publish-newsfeed "http://nf-two.html")
(publish-newsfeed "http://nf-three.html")))
(defmacro publish-newsfeed (url &optional (item-limit 5))
(flet ((get-text (s-tree node-path) (car (last (xmls-tools:find-subtree s-tree node-path)))))
(let ((rss-feed (xmls:parse (drakma:http-request url))))
`(:div :class "rss-feed"
(:a :href ,(get-text rss-feed '("channel" "link")) :target "_top" (:h1 ,(get-text rss-feed '("channel" "title"))))
(:ul ,@(mapcar #'(lambda (item)
`(:li (:a :href ,(get-text item '("link")) :target "_top" (:h2 ,(get-text item '("title"))))
(:p :class "date" ,(get-text item '("pubDate")))
(:p ,(get-text item '("description")))))
(let ((items (xmls-tools:find-all-children (xmls-tools:find-subtree rss-feed '("channel")) "item")))
(if (> (length items) item-limit) (subseq items 0 item-limit) items))))))))
But the result of the above is a "Server Error" page. I'm not quire sure why; page-template is a macro so the calls to publish-newsfeed shouldn't be expanded until they're in the context of with-html-output-to-string. Can anyone tell me what I'm doing wrong?
Also, on closer inspection of the various Hunchentoot/cl-who tutorials, none of them seems to do this kind of page composition. Can anyone with some Hunchentoot experience tell me what the correct/canonical way of decomposing a page into components is?
EDIT:
Correct response by Ramarren below; the with-html-output macros work under different evaluation rules. The version of publish-newsfeed that would actually work in this situation is actually
(defun publish-newsfeed (url &optional (item-limit 5))
(flet ((get-text (s-tree node-path) (car (last (xmls-tools:find-subtree s-tree node-path)))))
(let* ((rss-feed (xmls:parse (drakma:http-request url)))
(items (xmls-tools:find-all-children (xmls-tools:find-subtree rss-feed '("channel")) "item"))
(ltd-items (if (> (length items) item-limit) (subseq items 0 item-limit) items)))
(with-html-output
(*standard-output* nil :indent t)
(:div :class "rss-feed"
(:a :href (get-text rss-feed '("channel" "link")) :target "_top" (:h1 (str (get-text rss-feed '("channel" "title")))))
(:ul (dolist (item ltd-items)
(htm (:li (:h2 (:a :href (get-text item '("link")) :target "_top" (str (get-text item '("title")))))
(:p :class "date" (str (get-text item '("pubDate"))))
(:p (str (get-text item '("description")))))))))))))
Note the removal of mapcar for dolist (I'm a Schemer, don't give me too much of a hard time about liking lambdas, but they weren't the right choice here), and the use of htm to escape blocks of html s-exps (h-exps?) that wouldn't otherwise be in context for with-html-output. Finally, I had to wrap text but NOT :href properties in (str ) to get them to expand dynamically.