2011-05-05 11 views
6

que estoy tratando de conseguir una manija en el nuevo defprotocol, reify, etc.org.w3c.dom.NodeList a un Clojure ISEQ

Tengo un org.w3c.dom.NodeList regresaron de una llamada XPath y me gustaría "convertirlo" a un ISeq.

En Scala, he implementado un método de conversión implícita:

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 incluye métodos int getLength() y Node item(int index).

¿Cómo hago el equivalente en Clojure? Espero que necesite usar defprotocol. ¿Qué funciones necesito definir para crear un seq?

Si hago una conversión simple, ingenua, a una lista usando loop y recur, terminaré con una estructura no perezosa.

Respuesta

7

La mayor parte de las funciones de procesamiento de la secuencia de Clojure volver SEQs perezosos, incluyen los map y range funciones:

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

en cuenta la nota tipo para NodeList anterior no es necesaria, pero mejora el rendimiento.

Ahora puede utilizar esa función, así:

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

Utilice un for comprehension, estas secuencias de producción perezosas.

Aquí está el código para usted. Me tomé el tiempo para hacerlo ejecutable en la línea de comando; solo necesita reemplazar el nombre del archivo XML analizado.

Advertencia 1: evite definir sus variables. Use las variables locales en su lugar.

Advertencia 2: esta es la API de Java para XML, por lo que los objetos son mutables; ya que tiene una secuencia perezosa, si le sucede algún cambio al árbol DOM mutable mientras está iterando, puede que tenga desagradables cambios en la raza.

Advertencia 3: a pesar de que esta es una estructura perezoso, todo el árbol DOM ya está en la memoria de todos modos (No estoy muy seguro de esto último comentario, aunque creo que la API intenta aplazar la lectura. árbol en la memoria hasta que sea necesario, pero no hay garantías). Por lo tanto, si tiene problemas con documentos XML grandes, trate de evitar el enfoque 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

Nuestros mensajes cruzados, de lo contrario no habría molestado. Tu uso de 'para' se ve muy bien aquí. – Chouser

Cuestiones relacionadas