2010-05-20 6 views
9

में एक्सएमएल फाइलों पर जिपर पेड़ में सम्मिलन मैं उलझन में हूं कि clojure.contrib के zip-filter.xml के माध्यम से प्राप्त XML एक्स पेड़ को निष्क्रिय रूप से कैसे बदला जाए। ऐसा करने की कोशिश करनी चाहिए, या क्या कोई बेहतर तरीका है?क्लोजर

कहो मैं कुछ डमी xml फ़ाइल को "itemdb.xml" इस तरह है:

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

मैं कैसे clojure का उपयोग करने के बारे में स्पष्ट नहीं कर रहा हूँ। ज़िप इस मामले में उचित रूप से कार्य करता है, और यह ज़िप-फ़िल्टर के साथ कैसे इंटरैक्ट करता है।

यदि आप इस छोटे से उदाहरण में विशेष रूप से अजीब कुछ भी खोजते हैं, तो कृपया इसे इंगित करें।

+0

contrib.zip फिल्टर:

ज़िप फिल्टर के लिए एक वैकल्पिक (। मैं एक अधिक व्यापक जवाब बनाने के लिए जा रहा था लेकिन मीकल पहले से ही के रूप में एक बहुत अच्छा एक लिखित) लू ए है .xml अब https://github.com/clojure/data.zip/ – claj

उत्तर

8

सबसे पहले, आपको फ्रेड की परिभाषा में :content (और :contents नहीं) का उपयोग करना चाहिए।

जगह में है कि परिवर्तन के साथ

, निम्नलिखित काम करने के लिए लगता है:

(-> (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 बहुत समान है, वहाँ बनाने के लिए सिर्फ दो सुधार कर रहे हैं:

  1. zf/xml-> ज़िपर का एक अनुक्रम रिटर्न locs; zip/rightmost केवल एक स्वीकार करता है, इसलिए आपको पहले बाहर मछली बनाना होगा (इसलिए ऊपर में first);

  2. आपके द्वारा जिपर को संशोधित करने के बाद, आपको अंतर्निहित पेड़ (संशोधित संस्करण) पर वापस जाने के लिए zip/root का उपयोग करने की आवश्यकता है।

शैली पर अंतिम टिप्पणी के रूप में, print + format = printf। :-)

+0

में सुधार के लिए धन्यवाद है! यहां अभी भी कुछ अजीब व्यवहार है जो आपके कोड में अंतिम ज़िप/रूट के बाद ज़िप/एक्सएमएल-ज़िप जोड़कर हल किया जाता है। उस अतिरिक्त रेखा को जोड़ने में विफलता आपको एक से अधिक संलग्न करने से रोकती है ... स्पष्ट रूप से ज़िप/रूट एक जिपर नहीं लौटाता है, बस एक और स्थान, इसलिए एपेंड-आइटम द्वारा लौटाया गया प्रकार अभी भी सही नहीं होगा, लेकिन अच्छा अंत में lxml/emit के लिए पर्याप्त ... प्रिंटफ़ नोट के बारे में हंसना था ... आश्चर्यजनक है कि आप स्पष्ट रूप से बिना किसी चीज़ पर कितनी बार देख सकते हैं। ;-) – ivar

5

आपके द्वारा गलत टाइप किए गए आइटम में: सामग्री के लिए सामग्री और आपको शब्दावली के लिए सूचियों को प्राथमिकता देना चाहिए।

(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

मुझे [http://github.com/swannodette/enlive-tutorial/] को देखने के बाद एक नजदीकी नजर डालना होगा ... – ivar