Hunchentoot/cl-who ページ構成
実験的にhunchentootでいくつかのページをまとめようとしているのですが、思わぬ壁にぶち当たります。例として、次のテンプレート マクロがあります。
(defmacro page-template ((&key title) &body body)
`(with-html-output-to-string
(*標準出力* 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))))
今、純粋なテキストページ、または次のようなhtmlリテラルで満たされたページがある場合
(define-easy-handler (テストページ:uri "/") () (page-template (:title "Splash Page") (:p "Testing testing")))
すべて問題ありません。ページは適切に出力され、コードの作業をすぐに確認できます。しかし、冗長な要素で構成されたページがある場合、それはそれほど単純ではありません。たとえば、何らかの理由で 3 つの RSS ニュースフィードを表示したいページがあるとします。これは抽象化したい十分に複雑なコンポーネントなので、私の考えでは、次のようなことができるはずです
(define-easy-handler (test-feed :uri "/feeds") ()
(page-template (:title "Splash Page")
(パブリッシュ ニュースフィード "http://nf-one.html")
(パブリッシュ・ニュースフィード「http://nf-two.html」)
(publish-newsfeed "http://nf-three.html")))
(defmacro publish-newsfeed (url &optional (item-limit 5))
(flet ((get-text (s-tree ノードパス) (car (last (xmls-tools:find-subtree s-tree ノードパス)))))
(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 #'(ラムダ (アイテム)
`(: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 '("説明")))))
(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-who チュートリアルを詳しく調べたところ、この種のページ構成を行っているものはないようです。Hunchentoot の経験がある人なら、ページをコンポーネントに分解する正しい/標準的な方法を教えてもらえますか?
編集:
以下のRamarrenによる正しい応答。マクロはwith-html-output異なる評価ルールの下で機能します。この状況で実際に機能する publish-newsfeed のバージョンは、実際には
(defun publish-newsfeed (url &optional (item-limit 5))
(flet ((get-text (s-tree ノードパス) (car (last (xmls-tools:find-subtree s-tree ノードパス)))))
(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)))
(html出力付き
(*標準出力* 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 '("説明")))))))))))))
mapcarforが削除されていることに注意してくださいdolist(私はスキーマ担当者です。ラムダ式が好きなのであまり苦労しないでください。ただし、ここでは適切な選択ではありませんでした) htm。 (h-exps?) それ以外の場合は のコンテキストにはなりませんwith-html-output。最後に、動的に展開するために、:hrefプロパティではなくテキストをラップする必要がありました。(str )