【问题标题】:Recursion in html like data structure using clojure使用clojure在类似html的数据结构中递归
【发布时间】:2016-03-27 02:55:43
【问题描述】:

我一直在思考这个问题,但是我想不出构建我的函数的步骤:

我有一个打嗝之类的html数据作为输入,这个结构是由html和自定义元素组成的,例如:

格式:[标签名选项和正文]

[:a {} []] ;; simple
[:a {} [[:span {} []]]] ;; nested component
[:other {} []] ;; custom component at tag-name
[:a {} [[:other {} []]]] ;; custom component at body

每当结构有一个自定义元素时,我应该用database中的html表示来渲染(替换)它,自定义元素可能出现在tag-name或身体:

(def example
  [:div {} [[:a {} []]
            [:custom {} []]]])

    (def database {
      :custom [[:a {} []
               [:div {} []]})

(def expected-result
  [:div {} [[:a {} []]
            [:a {} []]
            [:div {} []]]])

问题是:如何创建一个获取这些数据的函数,查找组件的标签和主体,如果有自定义元素将其替换为database元素,替换后再次查看,如果有新组件,请再次执行此步骤...

我已经有一个函数(custom-component?),它接受一个标签名称,如果是一个自定义元素,则返回一个布尔值:

(custom-component? :a) ;; false
(custom-component? :test) ;; true

感谢您的帮助,我真的很困惑。

【问题讨论】:

  • 你检查过Reagent project吗?
  • @jmargolisvt 我只需要输出html,最后都是静态html(这是目标)

标签: recursion clojure hiccup


【解决方案1】:

clojure 有一种特殊的方式来完成这个任务——拉链: http://josf.info/blog/2014/03/28/clojure-zippers-structure-editing-with-your-mind/

这是您问题解决方案的一个粗略示例(我在您的 database 中添加了一个组件,以表明替换也在新添加的组件中递归发生):

(require '[clojure.zip :as z])

(def example
  [:div {} [[:custom2 {} []]
            [:a {} []]
            [:custom {} []]]])

(def database {:custom [[:a {} []]
                        [:div {} [[:custom2 {} [[:p {} []]]]]]]
               :custom2 [[:span {} [[:form {} []]]]]})

(defn replace-tags [html replaces]
  (loop [current (z/zipper
                  identity last
                  (fn [node items]
                    [(first node) (second node) (vec items)])
                  html)]
    (if (z/end? current)
      (z/root current)
      (if-let [r (-> current z/node first replaces)]
        (recur (z/remove (reduce z/insert-right current (reverse r))))
        (recur (z/next current))))))

在回复中:

user> (replace-tags example database)
[:div {} [[:span {} [[:form {} []]]] 
          [:a {} []] 
          [:a {} []] 
          [:div {} [[:span {} [[:form {} []]]]]]]]

但要注意:它不会计算替换中的循环,所以如果你有这样的循环依赖:

(def database {:custom [[:a {} []]
                        [:div {} [[:custom2 {} [[:p {} []]]]]]]
               :custom2 [[:span {} [[:custom {} []]]]]})

它会产生一个无限循环。

【讨论】:

  • 很好的答案!它让我更新了我对拉链的了解:) 不过有一个问题:由于输入是 Hiccup 标记,它可能在元素向量中“解包”了孩子(例如[:div "Child1" "Child2"])。不应该 branch? 函数而不是 identityvector?children 函数而不是 last(fn [[tag & xs]] (if (map? (first xs)) (next xs) xs))
  • 嗯,应该是这样吧。我的回答只为操作问题中的“打嗝式”结构提供了解决方案,而不是所有有效的打嗝语法。显然,必须仔细考虑所有变体以获得生产就绪的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-11-26
  • 2021-12-11
  • 1970-01-01
  • 2019-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多