使用clojure.data.xml从Clojure中发出XML.

Pau*_*ans 2 lisp clojure xml-serialization

我需要将Clojure数据结构序列化为XML,但我对如何发布集合感到磕磕绊绊.为了使这更具体,假设我有一个Clojure地图如下:

    (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}}}})
Run Code Online (Sandbox Code Playgroud)

这只是一个带有一个元素的地图,其值是一组"汽车"物品.现在,让我们假设我要序列化此映射以生成以下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>
Run Code Online (Sandbox Code Playgroud)

在网上搜索有关如何在Clojure中最佳解析/发出XML的文档,让我进入了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>"
Run Code Online (Sandbox Code Playgroud)

一个稍微复杂的例子:

    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>"
Run Code Online (Sandbox Code Playgroud)

在这里,您可以看到'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))))
Run Code Online (Sandbox Code Playgroud)

我希望这会起作用,但是它没有.问题是'element'函数的第3个参数不能是序列本身.

所以,在这一点上,我有点难过该做什么.我对Lisp和Clojure来说还是比较陌生的,所以如果我的下一个想法是愚蠢的话,请继续关注我.所以我的想法是,这是一个宏的用例吗?也就是说,我应该创建一个宏,它将汽车的一组(或任何碰撞)作为其输入,并将其项目作为单独的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"})
Run Code Online (Sandbox Code Playgroud)

至少在我看来,这样一个宏的输出将作为'element'函数的第三个参数,并且会产生我想要的目标.当然,我担心的是有一些完全明显的解决方案,我忽视了,并且在这里使用宏是错误的.非常感谢SO社区的任何帮助!先感谢您!

- 保罗

ama*_*loy 6

一般来说,您所要求的转换是不可能的,因为您有关于什么应该是属性以及什么是子元素的"隐藏"信息.您可以编写此自定义flatten-as-elements函数或其他任何函数,然后如果在整个过程中插入一堆特定于域的知识,您将能够序列化.

但实际上,你应该在clojure中使用XML的两种流行"表示"之一:将数据写为

{:tag :parking-lot
 :content [{:tag :car :attrs {:color "red", :make "nissan", :year 2003}}
           {:tag :car :attrs {:color "blue", :make "toyota", :year 2001}}
           {:tag :car :attrs {:color "black", :make "honda", :year 2010}}]}
Run Code Online (Sandbox Code Playgroud)

我认为data.xml可以相当简单地为您发射,或者使用更简洁的打嗝样式,带有多个元素的标签和列表的向量:

[:parking-lot (list [:car {:color "red", :make "nissan", :year 2003}]
                    [:car {:color "blue", :make "toyota", :year 2001}]
                    [:car {:color "black", :make "honda", :year 2010}])]
Run Code Online (Sandbox Code Playgroud)

你可以用它打印(emit (sexp-as-element [...])).


Mat*_*ard 5

您可以使用apply将参数拼接到函数调用中:

(emit-str
 (apply 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))))
Run Code Online (Sandbox Code Playgroud)