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) и затем соедините их, как указано выше. Т.е. спускаться с вершины, подбирать вещи с каждого из уровней, при необходимости вызывать метод, который далее обрабатывает дочерние элементы таким же образом (используя молнии).

Другими словами, я хочу:

  1. Создать молнию
  2. Переслать эту молнию одному из методов обработки
  3. Переместить молнию в определенное место
  4. Обработать это место
  5. Обработайте детей таким же образом (шаги 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?

Другие вопросы по тегам