这是一个举例说明我想做的事情:
(ns sample
(:require [clojure.zip :as zip]
[clojure.data.zip.xml :refer [attr text xml-> xml1->]]
[clojure.data.xml :as xml]))
;; From https://github.com/clojure/data.zip/blob/ca5a2efcc1c865baa25f904d7d9f027809b8f738/src/test/clojure/clojure/data/zip/xml_test.clj
(def atom1 (xml/parse-str "<?xml version='1.0' encoding='UTF-8'?>
<feed xmlns='http://www.w3.org/2005/Atom'>
<id>tag:blogger.com,1999:blog-28403206</id>
<updated>2008-02-14T08:00:58.567-08:00</updated>
<title type='text'>n01senet</title>
<link rel='alternate' type='text/html' href='http://n01senet.blogspot.com/'/>
<entry>
<id>1</id>
<published>2008-02-13</published>
<title type='text'>clojure is the best lisp yet</title>
<author><name>Chouser</name></author>
</entry>
<entry>
<id>2</id>
<published>2008-02-07</published>
<title type='text'>experimenting with vnc</title>
<author><name>agriffis</name></author>
</entry>
</feed>
"))
(def atom1z (zip/xml-zip atom1))
(defn get-entries-titles [z]
(xml-> z :entry :title text))
(defn get-entries [z]
(xml-> z :entry))
(defn get-titles [z]
(xml-> z :title))
(defn f1 []
(-> atom1z get-entries-titles))
(defn f2 []
(-> atom1z get-entries get-titles text))
运行f1
会产生预期结果:
("clojure is the best lisp yet" "experimenting with vnc")
运行f2
会抛出异常:
ClassCastException clojure.lang.LazySeq cannot be cast to clojure.lang.IFn clojure.zip/node (zip.clj:67)
我的目标是将处理分为几个步骤:
这样我可以将事物分成不同的方法。例如,我可能需要具有属于所拾取的XML的不同部分的元素的不同属性,从而导致输出集合是平坦的(例如,从atom1上方获取所有<id>
元素,从而生成向量ID)。
我希望有处理每种类型节点的方法(在上面的例子中,从feed
获取ID并从entry
获取ID)然后如上所述链接它们。即从顶部开始,从每个级别中选择内容,如果需要调用一个方法,以相同的方式进一步处理子级(使用拉链)。
换句话说 - 我想:
但是,基于f2
中的异常,看起来它不起作用。如何才能做到这一点?如果不是人们应该如何使用clojure.data.zip.xml,那么推荐的是什么,考虑到分解?
答案 0 :(得分:1)
我遇到了同样的问题。有一个非常简单的原因,你不能连续调用两个xml->
运算符。正如Alex xml->
已经提到的那样,返回一个seq。
你的问题有两个答案。
以惯用方式处理树(或XML文档)的一种方法是处理树的每个级别:
(map (fn [entry] (xml-> entry :title text))
(get-entries atom1z))
如果您真正想要的是组合拉链,那么您必须编写一个宏来构建最终拉链,如get-entries-titles中的拉链。但是,只有在实际帮助您时才应使用宏。仔细想想。为了处理XML,你在clojure.data.zip.xml中缺少什么?