用这个数据
(def html
'(html (head (title "the fortune cookie institute"))
(body
(h1 "Welcome to the Fortune Cookie Institute")
(p "Our fortunes are guaranteed accurate no matter what.")
(br)
(div (p "Like these"))
(ol
(li "You will gain weight")
(li "Taxes will rise")
(li "Fusion power will always be 50 years away"))
(br)
(p "Submit your own fortunes to [email protected]!"))))
选项 1:使用内置的 clojure walk
(require '[clojure.walk :refer [prewalk]])
(prewalk (fn [x] (if (= x 'p) 'h2 x)) html)
注意,walker 会继续遍历,会在列表头部以外的位置找到 'p(不符合预期)。
选项 2:使用 specter
(require '[com.rpl.specter :refer [ALL FIRST setval recursive-path]] )
(setval [ALL (recursive-path [] RECURSE
(cond-path
[sequential? FIRST (pred= 'p)] FIRST
sequential? [ALL RECURSE]))]
'h2
html)
这里的 specter 只会寻找列表头部位置的 'p(使用 sequential? 而不是 list?,因为你的结构非常接近 hiccup,它将使用向量。sequential 对列表和向量都适用。)
选项3
(defn shout [html]
(if-not (sequential? html)
html
(if (= 'p (first html))
(cons 'h2 (->> (rest html)
(map shout)))
(map shout html))))
我认为这确实会深度递归和消耗堆栈,但 HTML 的深度并不足以造成影响。我不确定是否存在一个更好的 loop [h html] ... (recur ...
答案。