gpt4 book ai didi

common-lisp - Hunchentoot/cl-who 页面组成

转载 作者:行者123 更新时间:2023-12-04 18:52:42 26 4
gpt4 key购买 nike

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 (test-page :uri "/") ()
(页面模板 (:title "Splash Page") (:p "Testing testing")))

一切都很好。页面输出正确,我可以立即看到我的代码所做的努力。但是,当我有一个由冗余元素组成的页面时,就没有那么简单了。例如,假设我有一个页面,无论出于何种原因,我想在该页面上显示三个 RSS 新闻提要。这是一个足够复杂的组件,我想将其抽象出来,所以在我看来,我应该能够做类似的事情

(define-easy-handler (test-feed :uri "/feeds") ()
(页面模板(:标题“启动页面”)
(发布新闻源“http://nf-one.html”)
(发布新闻源“http://nf-two.html”)
(发布新闻源“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)))))
(让 ((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")))))
(让((项目(xmls-tools:find-all-children(xmls-tools:find-subtree rss-feed '(“ channel ”))“项目”)))
(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宏在不同的评估规则下工作。在这种情况下实际工作的发布新闻源版本实际上是

(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)))))
(让* ((rss-feed (xmls:parse (drakma:http-request url))))
(项目 (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 '("description")))))))))))))

注意删除 mapcardolist (我是一名 Schemer,不要因为喜欢 lambdas 而给我太多困难,但它们在这里不是正确的选择),以及 htm 的使用转义 html s-exps (h-exps?) 块,否则这些块不会出现在 with-html-output 的上下文中.最后,我不得不换行但不是 :href(str ) 中的属性让它们动态扩展。

最佳答案

with-html-output-to-string使用 special evaluation rules 扩展它的 body .特别是,任何未识别的表单都保持原样,这意味着在生成 html 生成代码之前不会扩展宏,这意味着在您的 publish-newsfeed 之前。宏被标准编译器扩展,它不再在 with-html-output-to-string 的上下文中.这在扩展宏 manually 时很明显,尤其是使用 Slime 宏扩展功能。

为了让它工作,你应该做 publish-newsfeed一个函数和使用 with-html-output在它内部使用相同的流(要么假设到处都是标准输出,要么显式地传递流)。

关于common-lisp - Hunchentoot/cl-who 页面组成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3794223/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com