Множественные мутации XML-документа в Clojure

Я пробую clojure (впервые) для простого проекта. Мне нужно обновить дерево xml с помощью файла csv. Я читаю CSV-файл построчно, извлекаю некоторые значения, зацикливаю узел с некоторыми значениями и вставляю дочерний узел с другим значением.

Это отлично работает при первой вставке элемента. Второй раз получаю исключение NullPointerException (без следа). Я ищу корень из возвращаемого значения, которое я получаю от insert-child, и передаю этот корневой узел в следующий цикл. Каким-то образом вторая вставка не работает в этом корневом элементе. Кто-нибудь видит, что здесь происходит не так? Или отзыв об этом коде в целом, так как это моя первая попытка написать что-нибудь на 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))

person Jeroen    schedule 30.05.2012    source источник


Ответы (2)


не очень полезный NPE обычно означает, что вы куда-то сбежали с дерева.

я подозреваю, что вам не нужен вызов zip/root в insert-sqlpropertyname-elem.

person Arthur Ulfeldt    schedule 30.05.2012
comment
Проблема связана с возвращаемым значением функции insert-child. Если я не вызываю zip/root для структуры и выполняю запрос с помощью функции get-entity-node, она возвращает nil. Если я вызову zip/root, я получу NPE. Таким образом, возвращаемое значение из insert-child каким-то образом отличается от структуры данных исходного дерева молнии. Точнее, как мне преобразовать структуру данных, которая возвращается от insert-child, во что-то, что я могу запросить с помощью xml-›? - person Jeroen; 31.05.2012
comment
Как насчет замены (recur lines (dec index) (process-line (nth lines index) boc)) на (do (process-line (nth lines index) boc) (recur lines (dec index) boc)) - person Ankur; 31.05.2012

Хорошо, я не знаю, правильно ли это, но если я вызываю root в результате вставки-ребенка, а затем вызываю xml-zip в корне, все работает нормально. Не знаете, лучше ли архивировать всю структуру после каждой мутации?

person Jeroen    schedule 31.05.2012