У меня есть необходимость сериализации структуры данных Clojure для XML, но я натыкаюсь на то, как испускать коллекцию. Для того, чтобы сделать это более конкретным, предположим, что у меня есть карта Clojure следующим образом:Извлечение XML из Clojure с использованием clojure.data.xml.
(def parking-lot {:parking-lot #{
{:car {:color "red", :make "nissan", :year 2003}}
{:car {:color "blue", :make "toyota", :year 2001}}
{:car {:color "black", :make "honda", :year 2010}}}})
Это просто карта с одним элементом, значение которого представляет собой набор «автомобиль» пунктов. Теперь, давайте предположим, что я хочу, чтобы сериализовать эту карту, чтобы получить следующий XML:
<? xml version="1.0" ?>
<parking-lot>
<car color="red" make="nissan" year="2003" />
<car color="blue" make="toyota" year="2001" />
<car color="black" make="black" year="2010" />
</parking-lot>
Поиск в Интернете документы о том, как лучше всего разобрать/испускают XML в Clojure привели меня к clojure.data.xml библиотеке, так это то, что я используя.
Вот простой пример того, как использовать clojure.data.xml испустить некоторый XML:
REPL> (use 'clojure.data.xml)
=> nil
REPL> (emit-str (element :parking-lot {}))
=> "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<parking-lot></parking-lot>"
несколько более сложный пример:
REPL> (emit-str (element :parking-lot {}
(element :car {:color "yellow" :make "ford" :year "2000"})
(element :car {:color "purple" :make "chevrolet" :year "1977"})))
=> "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<parking-lot>
<car color=\"yellow\" year=\"2000\" make=\"ford\"></car>
<car color=\"purple\" year=\"1977\" make=\"chevrolet\"></car>
</parking-lot>"
Здесь вы видите, что третий аргумент функция «element» действительно может быть переменным числом вызовов «element». Не смотря глубоко на документы для функции «element», я предполагаю, что я предположил, что «элемент» будет перегружен, чтобы также взять последовательность элементов элемента в качестве третьего аргумента. И так, не глядя на документы, я просто пошел вперед и взбитыми небольшой блок кода, который будет делать только что:
REPL> (emit-str (element :parking-lot {}
(map (fn [car] (let [carattrs (:car car)]
(element :car {:color (:color carattrs),
:make (:make carattrs),
:year (:year carattrs)})))
(:parking-lot parking-lot))))
Я надеялся, что это будет работать, но, увы, это не так. Проблема в том, что третий аргумент функции «element» не может быть самой последовательностью.
Итак, на данный момент я немного тупик относительно того, что делать. Я все еще относительно новичок в Lisp и Clojure, так что легко, если моя следующая мысль будет придирчивой. Итак, моя мысль, будет ли это прецедентом для макроса? I.e., должен ли я создать макрос, который принимает в качестве своего ввода набор (или любой столбец для этого) машин и выводит его элементы как отдельные s-выражения? Так, например, я имею в виду, на мой взгляд макроса, который ведет себя так:
REPL> (defmacro flatten-as-elements [coll-of-cars] ...)
REPL> (flatten-as-elements #{ {:color "blue" :model "honda" year "2000"}
{:color "yellow" :model "ford" year "2011"}})
=> (element :car {:color "blue" :model "honda" year "2000"})
(element :car {:color "yellow" :model "ford" year "2011"})
В моем уме, по крайней мере, на выходе такого макроса будет соответствовать как 3-й аргумент функции «элемент» , и создаст мою желаемую цель. Конечно, я беспокоюсь, что есть совершенно очевидное решение, которое я игнорирую, и что использование макроса здесь ошибочно. Любая помощь сообщества SO очень ценится! Заранее спасибо!
-Поль