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 '("説明")))))))))))))
mapcar
forが削除されていることに注意してくださいdolist
(私はスキーマ担当者です。ラムダ式が好きなのであまり苦労しないでください。ただし、ここでは適切な選択ではありませんでした) htm
。 (h-exps?) それ以外の場合は のコンテキストにはなりませんwith-html-output
。最後に、動的に展開するために、:href
プロパティではなくテキストをラップする必要がありました。(str )