Multiple mutations to an XML document in Clojure

339 views Asked by At

I'm trying clojure (for the first time) for a simple project. I need to update an xml tree given a csv file. I'm reading the csv file line by line, extract some values, loop up a node given some values and insert a child node with another value.

This works fine the first time I insert an item. The second time I get a NullPointerException (without a trace). I lookup the root from the return value I get from insert-child and pass that root node to the next loop. Somehow the second insert fails on that root element. Anyone sees what's going wrong here? Or feedback in general on this code since this is my first attempt to write some Clojure.

(require 'clojure.string)
(require '[clojure.java.io :as io])
(require '[clojure.xml :as xml])
(require '[clojure.zip :as zip])
(require '[clojure.data.zip.xml :as zf])

(def business-object-config (xml/parse "BusinessObject.config"))
(def zipped (zip/xml-zip business-object-config ))

(defn sql-table-name [table-name]
  (second (re-matches #"(.*?)(Base|ExtensionBase|$)" table-name)))

(defn insert-sqlpropertyname-elem [loc name]
  (zip/root (zip/insert-child loc {:tag :SqlPropertyName :content [name]})))

(defn get-entity-node [table-name crm-name business-objects]
  (first (zf/xml-> business-objects :Entities
    :Entity [:CrmName (zf/text= (clojure.string/lower-case (sql-table-name table-name)))]
    :EntityItems
    :EntityItem [:CrmPropertyName (zf/text= (clojure.string/lower-case crm-name))])))

(defn process-line [line business-objects]
  (let [{crm-name 0 table-name 1 sql-name 6} (clojure.string/split line #";")
        node (get-entity-node table-name crm-name business-objects)]
    (insert-sqlpropertyname-elem node sql-name)))

(defn process-csv []
  (with-open
    [rdr (io/reader "input.csv")]
      (loop [lines (vec (take 5 (rest (line-seq rdr))))
             index (dec (count lines))
             boc zipped]
        (if (neg? index)
          boc
        (recur lines (dec index) (process-line (nth lines index) boc))))))

(spit "out.xml" (with-out-str (xml/emit (process-csv)) :pad true))
2

There are 2 answers

2
Arthur Ulfeldt On

the not-so-helpful NPE usually means you ran off the side of the tree somewhere.

i suspect you don't need the call to zip/root in insert-sqlpropertyname-elem.

0
Jeroen On

Ok, I don't know if it's the right way, but if I call root on the result of insert-child and than call xml-zip on the root everything works fine. Don't know if it's best practice to zip the entire structure after every mutation?