使用此数据
(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 ...
实现。