Search code examples
xmlclojurezipper

returning multiple values using clojure xml zipper


Lets suppose we have some XML like so:

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

Now, looking through the samples in zip_filter/xml.clj, I've figured out how to get to single values that I'm interested in.

I'm wondering how I would do something like return a list of pairs of text values of (c e).

EDIT:

Here is some working code, but it's pretty ugly. Not asking for trivial refactoring, but is there a nicer way that zippers give us to do this?

(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)))

Solution

  • Depending on the clojure version you use, you might find the juxt function useful. Your posted code (only relevant parts):

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