在 Clojure 中插入 XML 文件上的 Zipper 树 [英] Insertions into Zipper trees on XML files in Clojure
问题描述
我很困惑如何惯用地更改通过 clojure.contrib 的 zip-filter.xml 访问的 xml 树.应该尝试这样做,还是有更好的方法?
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?
说我有一些像这样的虚拟 xml 文件itemdb.xml":
Say that I have some dummy xml file "itemdb.xml" like this:
<itemlist>
<item id="1">
<name>John</name>
<desc>Works near here.</desc>
</item>
<item id="2">
<name>Sally</name>
<desc>Owner of pet store.</desc>
</item>
</itemlist>
我有一些代码:
(require '[clojure.zip :as zip]
'[clojure.contrib.duck-streams :as ds]
'[clojure.contrib.lazy-xml :as lxml]
'[clojure.contrib.zip-filter.xml :as zf])
(def db (ref (zip/xml-zip (lxml/parse-trim (java.io.File. "itemdb.xml")))))
;; Test that we can traverse and parse.
(doall (map #(print (format "%10s: %s
"
(apply str (zf/xml-> % :name zf/text))
(apply str (zf/xml-> % :desc zf/text))))
(zf/xml-> @db :item)))
;; I assume something like this is needed to make the xml tags
(defn create-item [name desc]
{:tag :item
:attrs {:id "3"}
:contents
(list {:tag :name :attrs {} :contents (list name)}
{:tag :desc :attrs {} :contents (list desc)})})
(def fred-item (create-item "Fred" "Green-haired astrophysicist."))
;; This disturbs the structure somehow
(defn append-item [xmldb item]
(zip/insert-right (-> xmldb zip/down zip/rightmost) item))
;; I want to do something more like this
(defn append-item2 [xmldb item]
(zip/insert-right (zip/rightmost (zf/xml-> xmldb :item)) item))
(dosync (alter db append-item2 fred-item))
;; Save this simple xml file with some added stuff.
(ds/spit "appended-itemdb.xml"
(with-out-str (lxml/emit (zip/root @db) :pad true)))
我不清楚在这种情况下如何适当地使用 clojure.zip 函数,以及它如何与 zip-filter 交互.
I am unclear about how to use the clojure.zip functions appropriately in this case, and how that interacts with zip-filter.
如果您在这个小例子中发现任何特别奇怪的地方,请指出.
If you spot anything particularly weird in this small example, please point it out.
推荐答案
首先,您应该在 Fred 的定义中使用 :content
(而不是 :contents
).
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
您的 append-item2
非常相似,只需进行两个更正:
Your append-item2
is very similar, there are just two corrections to make:
zf/xml->
返回拉链位置序列;zip/rightmost
只接受一个,所以你必须先找出一个(因此是上面的first
);
zf/xml->
returns a sequence of zipper locs;zip/rightmost
accepts just one, so you have to fish one out first (hence thefirst
in the above);
在完成对拉链的修改后,您需要使用 zip/root
返回(修改后的版本)底层树.
after you're done modifying the zipper, you need to use zip/root
to get back at (the modified version of) the underlying tree.
关于样式的最后说明,print
+ format
= printf
.:-)
As a final note on style, print
+ format
= printf
. :-)
这篇关于在 Clojure 中插入 XML 文件上的 Zipper 树的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!