Clojure data zip xml состав
Вот пример, чтобы проиллюстрировать, что я хотел сделать:
(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, в результате чего получается вектор идентификаторов).
Я хочу иметь методы, которые обрабатывают каждый тип узла (в приведенном выше примере получить идентификатор от feed
и получить идентификатор от entry
) и затем соедините их, как указано выше. Т.е. спускаться с вершины, подбирать вещи с каждого из уровней, при необходимости вызывать метод, который далее обрабатывает дочерние элементы таким же образом (используя молнии).
Другими словами, я хочу:
- Создать молнию
- Переслать эту молнию одному из методов обработки
- Переместить молнию в определенное место
- Обработать это место
- Обработайте детей таким же образом (шаги 2. - 5.), используя расположение, заданное в шаге 3
Тем не менее, похоже, что это не работает таким образом, на основе исключения в f2
, Как это может быть сделано? Если это не то, как следует использовать clojure.data.zip.xml, что было бы рекомендовано, учитывая разложение?
1 ответ
Я столкнулся с той же проблемой. Существует очень простая причина, почему вы не можете позвонить двум xml->
операторы подряд. Как уже упоминалось Алекс xml->
возвращает последовательность Есть два ответа на ваш вопрос. Один из способов идиоматической обработки дерева (или документа XML) - обработка каждого уровня дерева:
(map (fn [entry] (xml-> entry :title text))
(get-entries atom1z))
Если на самом деле вы хотите объединить молнии, то вам нужно написать макрос для создания окончательной молнии, такой как в get-records-title. Тем не менее, вы должны использовать макрос, только если он действительно вам помогает. Хорошо подумай. Что вы упускаете из clojure.data.zip.xml для обработки XML?