如何在Clojure中将XML转换为edn? [英] How to convert XML to edn in Clojure?
问题描述
我是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屋!