Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clojure: Pass 'expanded' optional args to function

I'm new to Clojure and I'm stuck on how to 'expand' a function's optional args so they can be sent to another function that uses optional args (but wants those args as keywords not a seq of keywords).

I'm parsing xml and if I hard code values as below my function works, it walks the xml and finds the value of 'title':

; zd was required like this
[clojure.data.zip.xml :as zd]
; ...
(defn get-node-value [parsed-xml & node-path]
  (zd/xml-> (zip/xml-zip parsed-xml) :item :title zd/text))

(get-node-value parsed-xml)

What I want to do is use 'node-path' to pass in any number of keywords, but when written as below it comes in as a sequence of keywords so it throws an exception:

(defn get-node-value [parsed-xml & node-path]
  (zd/xml-> (zip/xml-zip parsed-xml) node-path zd/text))

(get-node-value parsed-xml :item :title)
; ClassCastException clojure.lang.ArraySeq cannot be cast to clojure.lang.IFn  clojure.data.zip/fixup-apply (zip.clj:73)

thanks!

like image 624
kreek Avatar asked Jun 10 '12 22:06

kreek


2 Answers

Maybe you want:

(defn get-node-value [parsed-xml & node-path]
  (zd/xml-> (zip/xml-zip parsed-xml) ((apply comp (reverse node-path))) zd/text))

I can't test the above, so am working from analogy:

(-> {:a {:c 1}, :b 2} ((apply comp (reverse [:a :c]))))
1

However, if dAni's solution works, ignore me!

like image 20
andrew cooke Avatar answered Oct 01 '22 04:10

andrew cooke


I think you are looking for apply (http://clojuredocs.org/clojure_core/clojure.core/apply)

(defn get-node-value [parsed-xml & node-path]
  (let [params (concat node-path [zd/text])]
    (apply zd/xml-> (zip/xml-zip parsed-xml) params)))
like image 169
DanLebrero Avatar answered Oct 01 '22 05:10

DanLebrero