2016-03-27 12 views
1

を使用して、私はこの問題について考えてきたが、私は私の機能を構築するための手順を把握することはできません。再帰のClojure

私は、入力として、HTMLデータのようなしゃっくりを持って、この構造があります

フォーマット:[タグ名オプション& ]

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

たび番目HTMLとカスタム要素、例えば作曲

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

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

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

問題:電子構造は、私は、カスタム要素がタグ名またはで存在することができるdatabaseであるHTML表現でそれをレンダリングする(交換する)必要があり、カスタム要素を持っていますこのデータを受け取る関数を作成して、コンポーネントのタグとボディを探し出す方法、カスタム要素がある場合はdatabase要素で置き換えます。置き換えた後、新しいコンポーネントがあればこの手順を実行しますもう一度...

私はすでに機能を持っています(カスタムコンポーネントent?タグ名を取り、カスタム要素である場合はブール値を返します):任意の助け

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

おかげで、私は本当にこの上で立ち往生しています。

+0

[試薬プロジェクト](https://reagent-project.github.io/)をチェックしましたか? – jmargolisvt

+0

@jmargolisvt私は出力がちょうどhtmlを必要とし、最後はすべて静的なhtmlになります(これは目的です) –

答えて

4

Clojureのは、このタスクをfullfillingの特別な方法があります - ジッパー: http://josf.info/blog/2014/03/28/clojure-zippers-structure-editing-with-your-mind/

ここでは、あなたの質問の解決の不完全例である(私はそれを置き換える表示するようにすることも再帰的に起こり、あなたのdatabaseに1つの以上の成分を追加しました)新たに追加されたコンポーネントで:

(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)))))) 
REPLで

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

しかし、注意してください:それはあなたの交換の内部サイクルを計算していないので、あなたはこのような循環依存がある場合:

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

をそれが無限ループを生成します。

+2

偉大な答え!それは私にジッパーで私の知識をリフレッシュさせました:) 1つの質問:入力がHiccupマークアップであるため、要素ベクトルに子要素が "展開されている"ことがあります(例: '[:div" Child1 "" Child2 "]')。もし 'last'の代わりに' fn [[tag&xs]](if(map?(first xs))の代わりに 'identity'の代わりに' branch'関数を 'ベクトル' (次のxs)xs)) '? –

+0

まあ、おそらくそれはそのようにすべきです。私の答えは、すべての有効なヒカップの構文ではなく、オペラの質問からの "ヒカップのような"構造の解決策を提供するだけです。明らかに、生産準備ができているソリューションのすべてのバリエーションを注意深く考えなければなりません。 – leetwinski

+0

答えをありがとう、私はまだジッパーについて読んでいる。 –