2010-05-20 33 views
9

Tôi đang bối rối như thế nào để thay đổi thành phần một cây xml được truy cập thông qua tệp zip-filter.xml của clojure.contrib. Nên cố gắng để làm điều này ở tất cả, hoặc là có một cách tốt hơn?Chèn vào cây Zipper trên các tệp XML trong Clojure

Nói rằng tôi có một số giả tập tin xml "itemdb.xml" như thế này:

<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> 

Và tôi có một số mã:

(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))) 

Tôi không rõ về cách sử dụng các clojure. các hàm zip thích hợp trong trường hợp này và cách tương tác với bộ lọc zip.

Nếu bạn phát hiện ra bất kỳ điều gì đặc biệt kỳ lạ trong ví dụ nhỏ này, vui lòng chỉ ra.

+0

các contrib.zip lọc .xml hiện được chuyển đến https://github.com/clojure/data.zip/ – claj

Trả lời

8

Trước hết, bạn nên sử dụng :content (và không :contents) theo định nghĩa của Fred.

Với sự thay đổi ở vị trí, sau đây dường như làm việc:

(-> (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 của bạn là rất giống nhau, chỉ có hai sự điều chỉnh để thực hiện:

  1. zf/xml-> trả về một chuỗi các dây kéo locs; zip/rightmost chỉ chấp nhận một, vì vậy bạn phải cá một lần đầu tiên (do đó là first ở trên);

  2. sau khi bạn đã sửa đổi xong dây kéo, bạn cần sử dụng zip/root để quay lại (phiên bản sửa đổi của) cây bên dưới.

Là một lưu ý cuối cùng về phong cách, print + format = printf. :-)

+0

Cảm ơn bạn đã sửa chữa! Vẫn còn một số hành vi lạ ở đây dường như được giải quyết bằng cách thêm zip/xml-zip sau mã zip/root cuối cùng trong mã của bạn. Việc không thêm dòng thừa đó ngăn bạn làm nhiều hơn một phụ lục ... dường như zip/root không trả lại một dây kéo, chỉ là một vị trí khác, vì vậy loại trả về bởi mục phụ thêm sẽ vẫn không hoàn toàn đúng, nhưng tốt đủ cho lxml/phát ra ở cuối ... Phải cười về lưu ý printf ... tuyệt vời bao nhiêu lần bạn có thể nhìn chằm chằm vào một cái gì đó mà không nhìn thấy rõ ràng. ;-) – ivar

5

Trong mục tạo, bạn nhập sai: nội dung cho: nội dung và bạn nên ưu tiên vectơ vào danh sách cho chữ.

(. Tôi đã đi để làm cho một câu trả lời toàn diện hơn nhưng Michal như đã viết một khá tốt)

Một thay thế cho zip-lọc là 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)))) 
+1

Tôi sẽ phải phóng to hơn sau khi xem [http://github.com/swannodette/enlive-tutorial/] ... – ivar

Các vấn đề liên quan