【问题标题】:How to generate Hiccup structures conditionally?如何有条件地生成打嗝结构?
【发布时间】:2021-06-03 09:18:31
【问题描述】:

我有一堆描述位置的地图:

 (def pizzeria
  {
   :LocationId "pizzeria"
   :Desc       "Pizzeria where Timur works"
   :Address    "Vorgartenstraße 126, 1020 Wien"
   :Comment    ""
   })

(def dancing-school
  {
   :LocationId "dancing-school"
   :Desc       "Dancing school"
   :Comment    "4th district"
   })

其中一些地图有:Comments,而另一些则没有。

我想创建一个 Clojure 函数,其中包括将注释输出到 HTML(如果存在)。

我写了这个函数:

(defn render-location-details
  [cur-location]
  (let [
        desc (get cur-location :Desc)
        address (get cur-location :Address)
        comment (get cur-location :Comment)
        address-title [:h4 "Address"]
        address-body [:p address]
        comment-hiccup [
                        (if (clojure.string/blank? comment)
                          nil
                          [:div
                           [:h4 "Comment"]
                           [:p comment]
                           ])
                        ]
        ]
    [:h3 desc
     address-title
     address-body
     comment-hiccup
     ]
    )
  )

如果我运行使用此函数的代码,我会收到错误

Execution error (IllegalArgumentException) at
hiccup.compiler/normalize-element (compiler.clj:59).
 is not a valid element name.

如果我将comment-hiccup 更改为nil,错误就会消失。

如何使用 Hiccup 有条件地将数据输出到 HTML?

注意:我是 Clojure 的新手,所以如果我的方法完全错误,请告诉并展示如何正确操作。

【问题讨论】:

    标签: clojure hiccup


    【解决方案1】:

    您的第一次尝试将创建 comment-hiccup 喜欢:

    [nil]
    

    有效的打嗝总是以关键字标签开头,例如:

    [:h3 "hello"]
    [:div nil]
    

    所以错误消息基本上说nil 不是有效的html 标记。但是,在clojure中nil转换为字符串时长度为零,所以错误信息变为 is not a valid element name. 而不是foo is not a valid element name.

    但是,Hiccup 和许多类似的表单将接受 nil 而不是有效的 Hiccup 表达式,并在呈现剩余的有效表单之前将它们过滤掉。此功能的存在正是为了允许使用内联 ifwhen 表单,它们会产生有效的打嗝或 nil

    示例代码:

    (ns tst.demo.core
      (:use tupelo.core tupelo.test)
      (:require
        [hiccup.core :as h]))
    
    (dotest
      (is= (h/html [:p "bar"]) "<p>bar</p>")
      (is= (h/html [:p nil]) "<p></p>")
      (is= (h/html nil) "")
    
      ; if uncommented, this creates an error during macroexpansion of `h/html`
      ; (println :err1 (h/html [nil]))  ; <=== line 12
      ;    `Syntax error macroexpanding h/html at (tst/demo/core.clj:12:18). 
      ;       java.lang.IllegalArgumentException:  is not a valid element name.`
    
      )
    

    基于my favorite template project

    旁注: 诸如上述的隐秘错误消息是避免在您自己的代码中不必要地使用宏的一个强有力的理由。上述错误不是在代码执行过程中出现,而是在代码编译过程中出现。因此,即使我们用try/catch 包装有问题的行,我们也无法处理错误。


    附言

    大多数 clojurists 会将上述代码压缩成更“内联”的样式,例如:

    (defn render-location-details
      [cur-location]
      [:div
       [:h3 (:Desc cur-location)]
       [:h4 "Address"]
       [:p (:Address cur-location)]
       (when-not (clojure.string/blank? (:Comment cur-location))
         [:div
          [:h4 "Comment"]
          [:p (:Comment cur-location)]])])
    

    【讨论】:

      【解决方案2】:

      下面的代码似乎有效。仍然欢迎改进建议。

      (defn render-location-details
        [cur-location]
        (let [
              desc (get cur-location :Desc)
              address (get cur-location :Address)
              comment (get cur-location :Comment)
              address-title [:h4 "Address"]
              address-body [:p address]
              comment-hiccup (if (clojure.string/blank? comment)
                                nil
                                [:div
                                 [:h4 "Comment"]
                                 [:p comment]
                                 ])
      
              ]
          [:div
            [:h3 desc]
            address-title
            address-body
            comment-hiccup
           ]
          )
        )
      
      

      【讨论】:

      • @AlanThompson 此代码有效。没有的版本在问题部分。
      猜你喜欢
      • 1970-01-01
      • 2017-10-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-14
      • 2022-07-07
      • 1970-01-01
      相关资源
      最近更新 更多