使用以下数据
(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)
请注意,该遍历器会继续行走,并可能在列表头部之外的位置找到'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 ...
解决方案。