本文介绍了在Clojure中的XML文件上插入到Zipper树中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很困惑如何惯用地更改通过clojure.contrib的zip-filter.xml访问的xml树。



说我有一个虚拟的xml文件itemdb.xml,如下所示:

 < itemlist> 
< item id =1>
< name> John< / name>
< desc>在这附近工作。< / desc>
< / item>
< item id =2>
< name> Sally< / name>
< desc>宠物商店的拥有者。< / 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(zip / xml-zip(lxml / parse-trim java.io.File。itemdb.xml)))))

;;测试我们可以遍历和解析。
(doall(map#(print(format%10s:%s\\\

(apply str(zf / xml->%:name zf / text))
apply str(zf / xml->%:desc zf / text))))
(zf / xml-> @db:item)))

;我假设需要这样的东西,使xml标签
(defn create-item [name desc]
{:tag:item
:attrs {:id3}
:contents
(list {:tag:name:attrs {}:contents(list name)}
{:tag:desc:attrs {}:contents(list desc)})})

(def fred-item(create-itemFredGreen-haired天体物理学家))

;;这干扰了结构某种方式
(defn append-item [xmldb item]
(zip / insert-right( - > xmldb zip / down zip / rightmost)item))

;;我想做更像这样的事情
(defn append-item2 [xmldb item]
(zip / insert-right(zip / rightmost(zf / xml-> xmldb:item))item)

(dosync(alter db append-item2 fred-item))

;;保存这个简单的xml文件与一些添加的东西。
(ds / spitattached-itemdb.xml
(with -out-str(lxml / emit(zip / root @db):pad true)))

我不清楚如何在这种情况下适当地使用clojure.zip函数,以及如何与zip过滤器交互。



如果你在这个小例子中发现任何特别奇怪的事情,请指出。

解决方案

首先,您应该在Fred的定义中使用:content (而不是:contents p>

在这种情况下,以下情况似乎有效:

  - >(zf / xml-> @db:item);一个方便的方法来获取:item zipper首先是
;但是我们实际上只需要一个
zip / rightmost;第一个最右边的兄弟:item
;(在这种情况下是最后一个:item)
(zip / insert-right fred-item);插入Fred到右边
zip /根) ;获取修改后的XML映射,
;它是修改的拉链的根

您的 append-item2 非常相似,只有两个更正:


  1. zf / xml - > 返回一系列拉链位置; zip / rightmost 只接受一个,所以你必须先捕获一个(因此在上面的第一);


  2. 完成修改拉链后,您需要使用 zip / root


作为风格的最后一个注释, print + 格式 = printf 。 : - )


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?

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>

And I have some code:

(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\n"
       (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)))

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.

解决方案

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:

  1. 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);

  2. 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. :-)

这篇关于在Clojure中的XML文件上插入到Zipper树中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

11-01 18:34