4

这是一个示例来说明我想做的事情:

(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
  • 从 xml 中获取条目
  • 从条目中获取标题

这样我就可以把事情分成不同的方法。例如,我可能需要提取属于 XML 不同部分的元素的不同属性,从而生成一个扁平的输出集合(例如,<id>从 atom1 上获取所有元素,生成一个 ID 向量)。

我想要处理每种类型的节点的方法(在上面的示例中,从 获取 IDfeed并从 获取 ID entry)然后将它们链接起来。即从顶部下降,从每个级别中挑选东西,如果需要调用以相同方式进一步处理子项的方法(使用拉链)。

换句话说 - 我想:

  1. 创建一个拉链
  2. 将该拉链转发到一种处理方法
  3. 将拉链移动到特定位置
  4. 处理该位置
  5. 使用步骤 3 中设置的位置以相同的方式处理子项(步骤 2. - 5.)

但是,根据f2. 如何才能做到这一点?如果这不是人们应该如何使用 clojure.data.zip.xml,那么在考虑分解的情况下,推荐的会是什么?

4

1 回答 1

2

我遇到了同样的问题。不能xml->连续调用两个运算符有一个非常简单的原因。正如亚历克斯已经提到的那样,xml->返回一个序列。你的问题有两个答案。惯用处理树(或 XML 文档)的一种方法是处理树的每一层:

(map (fn [entry] (xml-> entry :title text))
 (get-entries atom1z))

如果您真正想要的是组合 zippers,那么您将不得不编写一个宏来构造一个最终的 zipper,就像 get-entries-titles 中的那样。但是,只有当它确实对您有帮助时,您才应该使用宏。谨慎思考。为了处理 XML,您从 clojure.data.zip.xml 中缺少什么?

于 2016-11-07T10:44:56.583 回答