I am new to clojure so please bear with me. I have a XML which looks like this
I would use data.zip (Formerly clojure.contrib.zip-filter). It provides a lot of xml-parsing power and it's easily capable of performing xpath like expressions. The README describes it as a System for filtering trees, and XML trees in particular.
Below I have some sample code for creating a "row" for the CSV file. The row is a map of the column name to the attribute value.
(ns work
(:require [clojure.xml :as xml]
[clojure.zip :as zip]
[clojure.contrib.zip-filter.xml :as zf]))
; create a zip from the xml file
(def zip (zip/xml-zip (xml/parse "data.xml")))
; pulls out a list of all of the root "Id" attribute values
(zf/xml-> zip (zf/attr :Id))
(defn value [xvar-zip]
"Finds the id and value for a particular element"
(let [id (-> xvar-zip zip/node :attrs :Id) ; manual access
value (zf/xml1-> xvar-zip ; use xpath like expression to pull value out
:Row ; need the row element
:Col ; then the column element
(zf/attr :Value))] ; and finally pull the Value out
{id value}))
; gets the "column-value" pair for a single column
(zf/xml1-> zip
(zf/attr= :Id "cdx9") ; filter on id "cdx9"
:XVar ; filter on XVars under it
(zf/attr= :Id "TrancheAnalysis.IndexDuration") ; filter on id
value) ; apply the value function on the result of above
; creates a map of every column key to it's corresponding value
(apply merge (zf/xml-> zip (zf/attr= :Id "cdx9") :XVar value))
I'm not sure how the xml would work with multiple Dictionary XVars, as it is a root element. If you need to, one of the other functions which is useful for this type of work is mapcat
, which cat
s all of the values returned from the mapping function.
There are some more examples in the test source as well.
One other big recommendation I have is to make sure you use a lot of small functions. You'll find things much easier to debug, test, and work with.