代码之家  ›  专栏  ›  技术社区  ›  Inaimathi

hunchentoot/cl谁的页面组成

  •  4
  • Inaimathi  · 技术社区  · 14 年前

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

    现在当我有一个纯文本页面,或者一个像

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

    一切都很好。页面输出正确,我可以立即看到我的代码所做的努力。但是,当我有一个由冗余元素组成的页面时,就不那么简单了。例如,假设我有一个页面,不管出于什么原因,我都想显示三个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 who教程,他们似乎都没有做这种页面撰写。任何有Hunchentoot经验的人都能告诉我将页面分解为组件的正确/规范方法是什么吗?


    编辑:

    以下由Ramarren作出的正确回应;The 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")))))))))))))

    注意移除 mapcar 对于 dolist (我是一个阴谋家,不要给我太多的时间来喜欢兰伯斯,但他们在这里不是正确的选择),以及使用 htm 要转义HTML s-exps块(h-exps?)如果不是这样的话 带HTML输出 . 最后,我不得不换行,但不是 :href 属性在 (str ) 使它们动态扩展。

    1 回复  |  直到 14 年前
        1
  •  5
  •   Ramarren    14 年前

    with-html-output-to-string 使用扩展其主体 special evaluation rules . 特别是,任何未识别的表单都保持原样,这意味着在生成HTML生成代码之前,宏不会展开,这意味着 publish-newsfeed 宏由不再位于上下文中的标准编译器展开 将HTML输出为字符串 . 这在扩展宏时很明显 manually 尤其是使用黏液的大膨胀特性。

    为了让它发挥作用,你应该 发布新闻源 功能和用途 with-html-output 在同一个流中` 标准输出 任何地方或明确地传递流)。