Convert org.w3c.dom.NodeList to Clojure ISeq

I am trying to get a handle to new defprotocol , reify , etc.

I have an org.w3c.dom.NodeList returned from an XPath call and I would like to "convert" it to ISeq.

In Scala, I applied an implicit conversion method:

 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 includes int getLength() and Node item(int index) methods.

How to make an equivalent in Clojure? I expect that I will need to use defprotocol . What functions do I need to define to create seq ?

If I do a simple, naive conversion to a list using loop and recur , I get an illogical structure.

+6
source share
2 answers

Most Clojure sequence processing functions return lazy sequences, including map and range functions:

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

Please note that the hint type for NodeList above is not needed, but it improves performance.

Now you can use this function as follows:

 (map #(.getLocalName %) (node-list-seq your-node-list)) 
+7
source

Use for understanding , it gives lazy sequences.

Here is the code for you. I took the time to run it on the command line; you only need to replace the name of the parsed XML file.

Caution 1: Avoid defining variables. Use local variables instead.

Caveat 2: This is the Java API for XML, so objects change; since you have a lazy sequence, if any changes happen to the mutable DOM tree during the replay, you may have unpleasant race changes.

Caveat 3: although this is a lazy structure, the whole DOM tree is already in memory anyway (I'm not quite sure about this last comment). I think the API is trying to defer reading the tree in memory until it is needed, but no guarantees). Therefore, if you run into problems with large XML documents, try to avoid the DOM approach.

 (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)) 
+6
source

Source: https://habr.com/ru/post/887364/


All Articles