如何在Clojure中将XML转换为edn? [英] How to convert XML to edn in Clojure?

查看:54
本文介绍了如何在Clojure中将XML转换为edn?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是Clojure的新手,并且想将我拥有的XML转换为edn对象.

I'm new to Clojure and would like to convert an XML I have into an edn object.

我读取的XML文件:

<Vehicle>
  <Model>Toyota</Model>
  <Color>Red</Color>
  <Loans>
    <Reoccuring>Monthly</Reoccuring>
    <Owners>
      <Owner>Bob</Owner>
    </Owners>
  </Loans>
  <Tires>
    <Model>123123</Model>
    <Size>23</Size>
  </Tires>
  <Engine>
    <Model>30065</Model>
  </Engine>
</Vehicle>

我将其保存为'test/resources/vehicle.xml

And I have saved it as 'test/resources/vehicle.xml

最终,我想拥有一个如下所示的EDN对象:

Ultimately, I would like to have a EDN object that looks like:

:Vehicle
    :Model "Toyota"
    :Color "Red"
    :Loans
        :Reoccuring "Monthly"
        :Owners
            :Owner "Bob"
    :Tires
        :Model 123123
        :Size 23
    :Engine
        :Model 30065

到目前为止,我在Clojure中尝试的是解析方法:

So far, what I have tried in Clojure is the parse method:

(def xml-parser
  (parse "<Vehicle><Model>Toyota</Model><Color>Red</Color><Loans><Reoccuring>Monthly</Reoccuring><Owners><Owner>Bob</Owner></Owners></Loans><Tires><Model>123123</Model><Size>23</Size></Tires><Engine><Model>30065</Model></Engine></Vehicle>"))

但是,这会返回如下所示的Clojure哈希:

However, this returns a Clojure hash that looks like:

{:tag :Vehicle, :attrs nil, :content [{:tag :Model, :attrs nil, :content ["Toyota"]} {:tag :Color, :attrs nil, :content ["Red"]} {:tag :Loans, :attrs nil, :content [{:tag :Reoccuring, :attrs nil, :content ["Monthly"]} {:tag :Owners, :attrs nil, :content [{:tag :Owner, :attrs nil, :content ["Bob"]}]}]} {:tag :Tires, :attrs nil, :content [{:tag :Model, :attrs nil, :content ["123123"]} {:tag :Size, :attrs nil, :content ["23"]}]} {:tag :Engine, :attrs nil, :content [{:tag :Model, :attrs nil, :content ["30065"]}]}]}

我在转换的最初步骤上遇到了麻烦.谢谢您的提前帮助.

I'm having trouble with this initial step of conversion. Thank you for your help in advance.

推荐答案

您拥有的数据为Enlive格式.使用 clojure.pprint/pprint 查看更好的格式:

The data you have is in Enlive format. Use clojure.pprint/pprint to see a nicer format:

{:tag :Vehicle,
 :attrs nil,
 :content
 [{:tag :Model, :attrs nil, :content ["Toyota"]}
  {:tag :Color, :attrs nil, :content ["Red"]}
  {:tag :Loans,
   :attrs nil,
   :content
   [{:tag :Reoccuring, :attrs nil, :content ["Monthly"]}
    {:tag :Owners,
     :attrs nil,
     :content [{:tag :Owner, :attrs nil, :content ["Bob"]}]}]}
  {:tag :Tires,
   :attrs nil,
   :content
   [{:tag :Model, :attrs nil, :content ["123123"]}
    {:tag :Size, :attrs nil, :content ["23"]}]}
  {:tag :Engine,
   :attrs nil,
   :content [{:tag :Model, :attrs nil, :content ["30065"]}]}]}

问题是您所需的输出实际上不是合法的EDN数据格式.但是,您可以使用 tupelo.forest 库在几种数据格式之间进行转换:

The problem is that your desired output is not actually legal EDN data format. However, you can use the tupelo.forest library to convert among several data formats:

首先声明数据并将其解析为Enlive格式:

First declare the data and parse it into Enlive format:

(ns tst.demo.core
  (:use tupelo.core tupelo.test)
  (:require
    [tupelo.parse.xml :as xml]
    [tupelo.forest :as tf])
  )

(def xml-str
   "<Vehicle>
      <Model>Toyota</Model>
      <Color>Red</Color>
      <Loans>
        <Reoccuring>Monthly</Reoccuring>
        <Owners>
          <Owner>Bob</Owner>
        </Owners>
      </Loans>
      <Tires>
        <Model>123123</Model>
        <Size>23</Size>
      </Tires>
      <Engine>
        <Model>30065</Model>
      </Engine>
    </Vehicle> ")

验证结果

(dotest
  (let [data-enlive (xml/parse xml-str)]
    (is= data-enlive
      {:tag     :Vehicle,
       :attrs   {},
       :content [{:tag :Model, :attrs {}, :content ["Toyota"]}
                 {:tag :Color, :attrs {}, :content ["Red"]}
                 {:tag     :Loans,
                  :attrs   {},
                  :content [{:tag :Reoccuring, :attrs {}, :content ["Monthly"]}
                            {:tag     :Owners,
                             :attrs   {},
                             :content [{:tag :Owner, :attrs {}, :content ["Bob"]}]}]}
                 {:tag     :Tires,
                  :attrs   {},
                  :content [{:tag :Model, :attrs {}, :content ["123123"]}
                            {:tag :Size, :attrs {}, :content ["23"]}]}
                 {:tag     :Engine,
                  :attrs   {},
                  :content [{:tag :Model, :attrs {}, :content ["30065"]}]}]})

转换为打ic格式:

    (is= (tf/enlive->hiccup data-enlive)
      [:Vehicle
       [:Model "Toyota"]
       [:Color "Red"]
       [:Loans [:Reoccuring "Monthly"]
        [:Owners [:Owner "Bob"]]]
       [:Tires [:Model "123123"]
        [:Size "23"]]
       [:Engine [:Model "30065"]]])

您也可能会喜欢布什"格式:

You may also like the "bush" format:

    (is= (tf/enlive->bush data-enlive)
      [{:tag :Vehicle}
       [{:tag :Model, :value "Toyota"}]
       [{:tag :Color, :value "Red"}]
       [{:tag :Loans}
        [{:tag :Reoccuring, :value "Monthly"}]
        [{:tag :Owners} [{:tag :Owner, :value "Bob"}]]]
       [{:tag :Tires}
        [{:tag :Model, :value "123123"}]
        [{:tag :Size, :value "23"}]]
       [{:tag :Engine} [{:tag :Model, :value "30065"}]]])

或更详细的树"格式

    (is= (tf/enlive->tree data-enlive)
      {:tag :Vehicle,
       :tupelo.forest/kids
            [{:tag :Model, :value "Toyota", :tupelo.forest/kids []}
             {:tag :Color, :value "Red", :tupelo.forest/kids []}
             {:tag :Loans,
              :tupelo.forest/kids
                   [{:tag :Reoccuring, :value "Monthly", :tupelo.forest/kids []}
                    {:tag :Owners,
                     :tupelo.forest/kids
                          [{:tag :Owner, :value "Bob", :tupelo.forest/kids []}]}]}
             {:tag :Tires,
              :tupelo.forest/kids
                   [{:tag :Model, :value "123123", :tupelo.forest/kids []}
                    {:tag :Size, :value "23", :tupelo.forest/kids []}]}
             {:tag :Engine,
              :tupelo.forest/kids
                   [{:tag :Model, :value "30065", :tupelo.forest/kids []}]}]})
    ))

请参见图珀洛森林文档有关完整的信息.

See the Tupelo Forest docs for full information.

以上代码是使用此模板项目运行的.

The above code was run using this template project.

如果您正在寻找分层的地图样式输出,则可以将类似的信息融合在一起:

If you are looking for a hierarchical map style output, you can kludge together something like so:

(ns tst.demo.core
  (:use tupelo.core tupelo.test)
  (:require [clojure.walk :as walk]))

(dotest
  (let [data  [:Vehicle
               [:Model "Toyota"]
               [:Color "Red"]
               [:Loans
                [:Reoccuring "Monthly"]
                [:Owners
                 [:Owner "Bob"]]]
               [:Tires
                [:Model "123123"]
                [:Size "23"]]
               [:Engine
                [:Model "30065"]]]

        mappy (walk/postwalk
                (fn [item]
                  (if (vector? item)
                    (if (= 2 (count item))
                      (conj {} item)
                      {(first item)
                       (into {} (rest item))})
                    item))
                data)]

有测试

    (is= mappy
      {:Vehicle
       {:Model  "Toyota",
        :Color  "Red",
        :Loans  {:Reoccuring "Monthly"
                 :Owners     {:Owner "Bob"}},
        :Tires  {:Model "123123"
                 :Size  "23"},
        :Engine {:Model "30065"}}})))

尽管如此,它还是很脆弱的.

Although this is pretty fragile as written.

这篇关于如何在Clojure中将XML转换为edn?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆