The Tupelo library può facilmente risolvere i problemi di questo tipo utilizzando struttura dati tupelo.forest
albero. Si prega di see this question for more information. Documenti API can be found here.
Qui cariciamo i dati xml e lo convertiamo prima in enlive e quindi nella struttura ad albero nativa utilizzata da tupelo.forest
. Libs dati & 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> ")
e l'inizializzazione di codice:
(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)
Il suffisso HID sta per "Hex ID", che è il valore esadecimale unico che si comporta come un puntatore a un nodo/foglia nell'albero .In questa fase abbiamo appena caricato i dati nella struttura dati forestali, la creazione di albero-1 che assomiglia a:
[: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 "]]
Togliamo prossimo tutte le stringhe vuote con questo codice:
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)
per produrre un molto più bello albero risultato (formato singhiozzo)
[: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"]]]]]
Il codice seguente calcola quindi le risposte alle tre domande di cui sopra:
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)]
con i risultati:
(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"]]]]))))
L'esempio completo può essere trovato in the forest-examples unit test.
Sarebbe disposto a modificare la risposta e aggiungere un esempio? – octopusgrabbus