首页 > 解决方案 > Clojure:将嵌套地图转换为仅保留特定属性的自定义地图

问题描述

我有一个地图矢量(xml/parse 的结果),其中包含以下嵌套地图矢量(我已经摆脱了一些我不想保留的部分):

[
{:tag :SoapObject, :attrs nil, :content [
    {:tag :ObjectData, :attrs nil, :content [
        {:tag :FieldName, :attrs nil, :content ["ID"]}
        {:tag :FieldValue, :attrs nil, :content ["8d8edbb6-cb0f-11e8-a8d5-f2801f1b9fd1"]}
    ]}
    {:tag :ObjectData, :attrs nil, :content [
        {:tag :FieldName, :attrs nil, :content ["Attribute_1"]}
        {:tag :FieldValue, :attrs nil, :content ["Value_1a"]}
    ]} 
    {:tag :ObjectData, :attrs nil, :content [
        {:tag :FieldName, :attrs nil, :content ["Attribute_2"]}
        {:tag :FieldValue, :attrs nil, :content ["Value_2a"]}
    ]} 
]}
{:tag :SoapObject, :attrs nil, :content [
    {:tag :ObjectData, :attrs nil, :content [
        {:tag :FieldName, :attrs nil, :content ["ID"]}
        {:tag :FieldValue, :attrs nil, :content ["90e39036-cb0f-11e8-a8d5-f2801f1b9fd1"]}
    ]}
    {:tag :ObjectData, :attrs nil, :content [
        {:tag :FieldName, :attrs nil, :content ["Attribute_1"]}
        {:tag :FieldValue, :attrs nil, :content ["Value_1b"]}
    ]}
    {:tag :ObjectData, :attrs nil, :content [
        {:tag :FieldName, :attrs nil, :content ["Attribute_2"]}
        {:tag :FieldValue, :attrs nil, :content ["Value_2b"]}
    ]}
]}
]

现在我想从这个结构中只提取一些特定的数据,产生如下所示的结果:

[
{"ID" "8d8edbb6-cb0f-11e8-a8d5-f2801f1b9fd1",
"Attribute_1" "Value_1a",
"Attribute_2" "Value_1a"}

{"ID" "90e39036-cb0f-11e8-a8d5-f2801f1b9fd1",
"Attribute_1" "Value_1b",
"Attribute_2" "Value_1b"}
]

哪个clojure工具可以帮助我完成这个?

我发现了另一个有点相似的问题,但是每当我尝试某个版本的 map 调用时,我得到的结果是某种 clojure.lang.LazySeq 或 clojure.core$map,我无法正确打印来验证结果。

标签: clojuretransformation

解决方案


通常你可以从底部开始,逐渐向上:

首先,您要解析 attr 项:

(def first-content (comp first :content))

(defn get-attr [{[k v] :content}]
  [(first-content k)
   (first-content v)])

user> (get-attr {:tag :ObjectData, :attrs nil, :content [
        {:tag :FieldName, :attrs nil, :content ["ID"]}
        {:tag :FieldValue, :attrs nil, :content ["90e39036-cb0f-11e8-a8d5-f2801f1b9fd1"]}
        ]})
;;=> ["ID" "90e39036-cb0f-11e8-a8d5-f2801f1b9fd1"]

然后你会把每个项目变成一个属性图:

(defn parse-item [item]
  (into {} (map get-attr (:content item))))

(parse-item {:tag :SoapObject, :attrs nil, :content [
    {:tag :ObjectData, :attrs nil, :content [
        {:tag :FieldName, :attrs nil, :content ["ID"]}
        {:tag :FieldValue, :attrs nil, :content ["90e39036-cb0f-11e8-a8d5-f2801f1b9fd1"]}
    ]}
    {:tag :ObjectData, :attrs nil, :content [
        {:tag :FieldName, :attrs nil, :content ["Attribute_1"]}
        {:tag :FieldValue, :attrs nil, :content ["Value_1b"]}
    ]}
    {:tag :ObjectData, :attrs nil, :content [
        {:tag :FieldName, :attrs nil, :content ["Attribute_2"]}
        {:tag :FieldValue, :attrs nil, :content ["Value_2b"]}
    ]}
]})

;;=> {"ID" "90e39036-cb0f-11e8-a8d5-f2801f1b9fd1", "Attribute_1" "Value_1b", "Attribute_2" "Value_2b"}

所以你需要做的最后一件事是映射顶级表单,产生所需的结果:

(mapv parse-item data)

;;=> [{"ID" "8d8edbb6-cb0f-11e8-a8d5-f2801f1b9fd1", "Attribute_1" "Value_1a", "Attribute_2" "Value_2a"} 
;;    {"ID" "90e39036-cb0f-11e8-a8d5-f2801f1b9fd1", "Attribute_1" "Value_1b", "Attribute_2" "Value_2b"}]

推荐阅读