The Tupelo library可以很容易地解決類似這樣的使用tupelo.forest
樹狀數據結構的問題。請see this question for more information。 API文檔can be found here。
在這裏,我們加載你的xml數據,並將其首先轉化爲有活力,然後使用tupelo.forest
使用的本地樹結構。利布斯&數據DEF:
(ns tst.tupelo.forest-examples
(:use tupelo.forest tupelo.test)
(:require
[clojure.data.xml :as dx]
[clojure.java.io :as io]
[clojure.set :as cs]
[net.cgrand.enlive-html :as en-html]
[schema.core :as s]
[tupelo.core :as t]
[tupelo.string :as ts]))
(t/refer-tupelo)
(def xml-str-prod "<data>
<products>
<product>
<section>Red Section</section>
<images>
<image>img.jpg</image>
<image>img2.jpg</image>
</images>
</product>
<product>
<section>Blue Section</section>
<images>
<image>img.jpg</image>
<image>img3.jpg</image>
</images>
</product>
<product>
<section>Green Section</section>
<images>
<image>img.jpg</image>
<image>img2.jpg</image>
</images>
</product>
</products>
</data> ")
和初始化代碼:
(dotest
(with-forest (new-forest)
(let [enlive-tree (->> xml-str-prod
java.io.StringReader.
en-html/html-resource
first)
root-hid (add-tree-enlive enlive-tree)
tree-1 (hid->hiccup root-hid)
在HID後綴代表「十六進制ID」,它是作用就像一個指向節點/葉在樹中唯一的十六進制值。在這個階段,我們剛剛加載在林中的數據結構中的數據,創建樹-1,它看起來像:
[:data
[:tupelo.forest/raw "\n "]
[:products
[:tupelo.forest/raw "\n "]
[:product
[:tupelo.forest/raw "\n "]
[:section "Red Section"]
[:tupelo.forest/raw "\n "]
[:images
[:tupelo.forest/raw "\n "]
[:image "img.jpg"]
[:tupelo.forest/raw "\n "]
[:image "img2.jpg"]
[:tupelo.forest/raw "\n "]]
[:tupelo.forest/raw "\n "]]
[:tupelo.forest/raw "\n "]
[:product
[:tupelo.forest/raw "\n "]
[:section "Blue Section"]
[:tupelo.forest/raw "\n "]
[:images
[:tupelo.forest/raw "\n "]
[:image "img.jpg"]
[:tupelo.forest/raw "\n "]
[:image "img3.jpg"]
[:tupelo.forest/raw "\n "]]
[:tupelo.forest/raw "\n "]]
[:tupelo.forest/raw "\n "]
[:product
[:tupelo.forest/raw "\n "]
[:section "Green Section"]
[:tupelo.forest/raw "\n "]
[:images
[:tupelo.forest/raw "\n "]
[:image "img.jpg"]
[:tupelo.forest/raw "\n "]
[:image "img2.jpg"]
[:tupelo.forest/raw "\n "]]
[:tupelo.forest/raw "\n "]]
[:tupelo.forest/raw "\n "]]
[:tupelo.forest/raw "\n "]]
接下來,我們刪除所有空白字符串與此代碼:
blank-leaf-hid? (fn [hid] (and (leaf-hid? hid) ; ensure it is a leaf node
(let [value (hid->value hid)]
(and (string? value)
(or (zero? (count value)) ; empty string
(ts/whitespace? value)))))) ; all whitespace string
blank-leaf-hids (keep-if blank-leaf-hid? (all-hids))
>> (apply remove-hid blank-leaf-hids)
tree-2 (hid->hiccup root-hid)
產生好得多的結果樹(打嗝格式)
[:data
[:products
[:product
[:section "Red Section"]
[:images [:image "img.jpg"] [:image "img2.jpg"]]]
[:product
[:section "Blue Section"]
[:images [:image "img.jpg"] [:image "img3.jpg"]]]
[:product
[:section "Green Section"]
[:images [:image "img.jpg"] [:image "img2.jpg"]]]]]
下面的代碼然後計算解答上述三個問題:
個
product-hids (find-hids root-hid [:** :product])
product-trees-hiccup (mapv hid->hiccup product-hids)
img2-paths (find-paths-leaf root-hid [:data :products :product :images :image] "img2.jpg")
img2-prod-paths (mapv #(drop-last 2 %) img2-paths)
img2-prod-hids (mapv last img2-prod-paths)
img2-trees-hiccup (mapv hid->hiccup img2-prod-hids)
red-sect-paths (find-paths-leaf root-hid [:data :products :product :section] "Red Section")
red-prod-paths (mapv #(drop-last 1 %) red-sect-paths)
red-prod-hids (mapv last red-prod-paths)
red-trees-hiccup (mapv hid->hiccup red-prod-hids)]
帶結果:
(is= product-trees-hiccup
[[:product
[:section "Red Section"]
[:images
[:image "img.jpg"]
[:image "img2.jpg"]]]
[:product
[:section "Blue Section"]
[:images
[:image "img.jpg"]
[:image "img3.jpg"]]]
[:product
[:section "Green Section"]
[:images
[:image "img.jpg"]
[:image "img2.jpg"]]]])
(is= img2-trees-hiccup
[[:product
[:section "Red Section"]
[:images
[:image "img.jpg"]
[:image "img2.jpg"]]]
[:product
[:section "Green Section"]
[:images
[:image "img.jpg"]
[:image "img2.jpg"]]]])
(is= red-trees-hiccup
[[:product
[:section "Red Section"]
[:images
[:image "img.jpg"]
[:image "img2.jpg"]]]]))))
完整例子可以發現in the forest-examples unit test。
你願意編輯你的答案並添加一個例子嗎? – octopusgrabbus 2012-07-18 18:35:40