I\'m confused as how to idiomatically change a xml tree accessed through clojure.contrib\'s zip-filter.xml. Should be trying to do this at all, or is there a better way?
In create-item you mistyped :contents for :content and you should prefer vectors to lists for literals.
(I was going to make a more comprehensive answer but Michal as already written a pretty good one.)
An alternative to zip-filter is Enlive:
(require '[net.cgrand.enlive-html :as e]) ;' <- fix SO colorizer
(def db (ref (-> "itemdb.xml" java.io.File. e/xml-resource))
(defn create-item [name desc]
{:tag :item
:attrs {:id "3"}
:content [{:tag :name :attrs {} :content [name]}
{:tag :desc :attrs {} :content [desc]}]})
(def fred-item (create-item "Fred" "Green-haired astrophysicist."))
(dosync (alter db (e/transformation [:itemlist] (e/append fred-item))))
Firstly, you should use :content
(and not :contents
) in your definition of Fred.
With that change in place, the following seems to work:
(-> (zf/xml-> @db :item) ; a convenient way to get to the :item zipper locs
first ; but we actually need just one
zip/rightmost ; let's move to the rightmost sibling of the first :item
; (which is the last :item in this case)
(zip/insert-right fred-item) ; insert Fred to the right
zip/root) ; get the modified XML map,
; which is the root of the modified zipper
Your append-item2
is very similar, there are just two corrections to make:
zf/xml->
returns a sequence of zipper locs; zip/rightmost
accepts just one, so you have to fish one out first (hence the first
in the above);
after you're done modifying the zipper, you need to use zip/root
to get back at (the modified version of) the underlying tree.
As a final note on style, print
+ format
= printf
. :-)