2010-09-25 35 views
4

Hunchentoot/CL-誰頁面構成Hunchentoot/CL-誰頁組合

我試圖拼湊幾頁中hunchentoot作爲一個實驗,我快到一個意想不到的牆。作爲一個例子,我有以下模板宏。

(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 "[email protected][~A - ~]Test Site" title))) 
      (:body ,@body))))

現在,當我有一個純文本頁面,還是一個充滿了HTML文本像

(define-easy-handler (test-page :uri "/")() 
    (page-template (:title "Splash Page") (:p "Testing testing")))

一切都OK。該頁面輸出正確,我可以立即看到我的代碼的努力。但是,當我有一個由冗餘元素組成的頁面時,並不那麼簡單。例如,假設我有一個頁面,無論出於何種原因,我想顯示三個RSS新聞傳遞。這是一個足夠複雜的成分,我想它抽象出來,所以我minnd,我應該能夠做到像

(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))))))))

但上述結果是「服務器錯誤」頁面。我不確定爲什麼; page-template是一個宏,因此publish-newsfeed的調用只有在with-html-output-to-string的情況下才能擴展。誰能告訴我我做錯了什麼?

此外,仔細檢查各種Hunchentoot/cl-誰教程,他們似乎沒有一個這樣的頁面組成。具有Hunchentoot經驗的任何人都可以告訴我,將頁面分解爲組件的正確/規範方法是什麼?


編輯:

通過下面Ramarren正確響應; with-html-output宏在不同的評估規則下工作。發佈 - 新聞推送的是實際上在這種情況下工作的版本實際上是

(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")))))))))))))

注意去除mapcardolist(我是一個陰謀家,不要給我太多的困難時期大約喜歡lambda表達式,但他們不是這裏的正確選擇),並且使用htm來轉義不會在with-html-output上下文中的html s-exps(h-exps?)塊。最後,我必須包裝文字,但不要(str)中的:href屬性使它們動態擴展。

回答

5

with-html-output-to-string使用special evaluation rules擴展其主體。特別是,任何未被識別的表格都保持原樣,這意味着在生成html生成代碼之前,宏不會被擴展,這意味着在您的publish-newsfeed宏由標準編譯器擴展時,它不再處於with-html-output-to-string的上下文中。擴展宏manually時這很明顯,特別是使用粘液宏展開功能。

爲了使它工作,你應該讓publish-newsfeed的功能和使用with-html-output內配置有相同的流(或者假設到處`標準輸出或顯式傳遞流)。