2011-05-05 20 views
6

我試圖讓新defprotocolreify手柄等轉換一個org.w3c.dom.NodeList到Clojure的ISEQ

我有一個org.w3c.dom.NodeList從一個XPath調用返回,我想將其轉換爲ISeq。

在Scala中,我實現的隱式轉換方法:

implicit def nodeList2Traversable(nodeList: NodeList): Traversable[Node] = { 
    new Traversable[Node] { 
    def foreach[A](process: (Node) => A) { 
     for (index <- 0 until nodeList.getLength) { 
     process(nodeList.item(index)) 
     } 
    } 
    } 
} 

NodeList包括這樣的方法和int getLength()Node item(int index)

我該怎麼做Clojure中的等價物?我期望我將需要使用defprotocol。我需要定義哪些功能來創建seq

如果我使用looprecur做一個簡單的,天真的轉換爲列表,我將最終得到一個非惰性結構。

回答

7

大多數Clojure的序列處理函數返回懶seqs,包括maprange功能:

(defn node-list-seq [^org.w3c.dom.NodeList node-list] 
    (map (fn [index] (.item node-list index)) 
     (range (.getLength node-list)))) 

注意上面的節點列表類型的提示是沒有必要的,但提高了性能。

現在你可以使用這個函數像這樣:

(map #(.getLocalName %) (node-list-seq your-node-list)) 
6

使用for comprehension,這些產生惰性序列。

這裏是你的代碼。我花時間在命令行上運行它;您只需要替換解析的XML文件的名稱即可。

注意事項1:避免定義變量。改用局部變量。

注意事項2:這是用於XML的Java API,所以對象是可變的;由於你有一個懶惰的序列,如果迭代時發生可變DOM樹的任何變化,你可能會有不愉快的種族變化。

買者3:即使這是一個懶惰的結構,整個DOM樹已經在內存反正(我真的不知道這最後的評論,但我認爲該API試圖推遲讀取。樹在內存中直到需要,但不保證)。因此,如果遇到大型XML文檔遇到麻煩,請儘量避免使用DOM方法。

(require ['clojure.java.io :as 'io]) 
(import [javax.xml.parsers DocumentBuilderFactory]) 
(import [org.xml.sax InputSource]) 

(def dbf (DocumentBuilderFactory/newInstance)) 
(doto dbf 
    (.setValidating false) 
    (.setNamespaceAware true) 
    (.setIgnoringElementContentWhitespace true)) 
(def builder (.newDocumentBuilder dbf)) 
(def doc (.parse builder (InputSource. (io/reader "C:/workspace/myproject/pom.xml")))) 

(defn lazy-child-list [element] 
    (let [nodelist (.getChildNodes element) 
     len (.getLength nodelist)] 
    (for [i (range len)] 
     (.item nodelist i)))) 

;; To print the children of an element 
(-> doc 
    (.getDocumentElement) 
    (lazy-child-list) 
    (println)) 

;; Prints clojure.lang.LazySeq 
(-> doc 
    (.getDocumentElement) 
    (lazy-child-list) 
    (class) 
    (println)) 
+0

我們的崗位交叉,否則我不會打擾你了。 'for'在這裏看起來很不錯。 – Chouser 2011-05-05 14:09:56