2010-01-09 1 views
4

Давайте предположим, что мы имеем некоторые XML следующим образом:возвращение нескольких значений с помощью Clojure XML застежку

<a> 
    <b> 
    <c>text</c> 
    <d> 
     <e>text</e> 
     <f> 
     ... lots of cruft here .. 
     </f> 
    </d> 
    </b> 
    <b> 
    ... 
    </b> 
    <!-- more b sub-trees --> 
</a> 

Теперь, просматривая образцы в zip_filter/xml.clj, я понял, как добраться до отдельных значений что меня интересует.

Мне интересно, как бы я сделал что-то вроде возврата списка пар текстовых значений (ce).

EDIT:

Вот некоторые рабочий код, но это довольно некрасиво. Не спрашивайте о тривиальном рефакторинге, но есть ли лучший способ, которым молнии дают нам это?

(defn extract-data [xml] 
    (let [items (x/xml-> xml zf/descendants :Item)  ;items not top-level 
     getAttributes #(x/xml1-> % :ItemAttributes) ;items have itemattributes 
     getASIN  #(x/xml1-> % :ASIN x/text) ;items have ASINs 
     getTitle  #(x/xml1-> % :Title x/text) ;itemattributes have Titles 
     getAuthor  #(x/xml1-> % :Author x/text)] ;itemattributes have Authors 
    (map 
     ;build a function to get everything we need from the items, and apply 
     #(let [attributes (getAttributes %)] ;get the attributes, we'll use it twice 
     (list 
      (getASIN %) 
      (getTitle attributes) 
      (getAuthor attributes))) 
     items))) 

ответ

4

В зависимости от версии Clojure вы используете, вы можете найти функция juxt полезна. Ваш адрес (только соответствующие разделы):

(defn extract-data 
    [xml] 
    (let [...] 
    (map (juxt getASIN (comp getTitle getAttributes) (comp getAuthor getAttributes)) items)))) 
+0

+1 для того, чтобы показать мне пример и более чистый способ выложить это. Попробуем это в ближайшее время. – z5h

+0

Прохладный. Я также могу сделать это, чтобы избежать 2 вызовов getAttributes. '(map (juxt getASIN (comp (juxt getTitle getAuthor) getAttributes))), но тогда мне нужно сгладить вектор. – z5h

2

Я уверен, что есть способ лучше, но это делает работу:

(letfn [(get-tag [tag coll] (:content (first (filter #(= tag (:tag %)) coll))))] 
    (map #(list (get-tag :c %) (get-tag :e (get-tag :d %))) 
     (map :content (:content (clojure.xml/parse "foo.xml"))))) 

результаты в

((["ctext1"] ["etext1"]) (["ctext2"] ["etext2"])) 
+0

Спасибо, я просто разместил некоторый фактический код для реальной структуры данных, с которой я работаю. +1 для показа мне letfn и одного из способов сделать это. – z5h

+0

Ах, не беспокойтесь. –