将org.w3c.dom.NodeList转换为Clojure ISeq

Ral*_*lph 6 collections clojure

我试图让新的句柄defprotocol,reify

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))
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

NodeList包括方法int getLength()Node item(int index).

我如何在Clojure中做相同的操作?我希望我需要使用defprotocol.我需要定义哪些函数才能创建seq

如果我使用loop和做一个简单,天真的转换到列表recur,我将最终得到一个非惰性结构.

Cho*_*ser 7

大多数Clojure的序列处理函数返回lazy seqs,包括maprange函数:

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

请注意,上面的NodeList类型提示不是必需的,但可以提高性能.

现在您可以像这样使用该功能:

(map #(.getLocalName %) (node-list-seq your-node-list))
Run Code Online (Sandbox Code Playgroud)


Leo*_*nel 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))
Run Code Online (Sandbox Code Playgroud)