使用以下数据
(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 ...
的答案。