5

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 )

4

1 に答える 1

6

マクロは、特別な評価ルールwith-html-output-to-stringを使用して本体を拡張します。特に、認識されないフォームはそのまま残されます。つまり、html生成コードが生成される前にマクロは展開されません。つまり、マクロが標準コンパイラによって展開されるまでに、のコンテキストではなくなります。これは、特にスライムマクロ展開機能を使用してマクロを手動で展開する場合に明らかです。publish-newsfeedwith-html-output-to-string

それを機能させるには、関数を作成し、その内部で同じストリームをpublish-newsfeed使用する必要があります( ` standard-outputをどこでも想定するか、ストリームを明示的に渡します)。with-html-output

于 2010-09-25T19:18:18.813 に答える