首页 > 解决方案 > 如何有条件地生成打嗝结构?

问题描述

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

 (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-hiccupnil,则错误消失。

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

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

标签: clojurehiccup

解决方案


您的第一次尝试将创建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.`

  )

基于我最喜欢的模板项目

旁注: 上述隐秘的错误消息是避免在您自己的代码中不必要地使用宏的一个强有力的理由。上述错误不是在代码执行过程中出现,而是在代码编译过程中出现。因此,即使我们用 . 包裹违规行,我们也无法处理错误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)]])])

推荐阅读