如何在Clojure中转换对象键和值

3

我正在使用Datomic,尽管这对于这个问题并不特别重要。但它通常返回带命名空间的键(枚举值也作为命名空间关键字返回)。我想将可能嵌套的结构翻译成剥离键和值的命名空间(并且字符串化枚举类型的值)。我这样做是因为我将在JSON REST API中返回结果,在那种情况下命名空间并没有太多意义。这里有一个简单的示例结构:

{ 
    :person/name "Kevin"
    :person/age 99
    :person/gender :gender/M
    :person/address {
        :address/state :state/NY
        :address/city "New York"
        :address/zip "99999"
    }
}

And I'm hoping to translate to:

{ 
    :name "Kevin"
    :age 99
    :gender "M"
    :address {
        :state "NY"
        :city "New York"
        :zip "99999"
    }
}

我知道可以使用(postwalk-replace {:person/name :name :person/age :age :person/gender :gender :person/address :address :address/city :city :address/state :state :address/zip :zip} the-entity)来覆盖键,但不包括值。

还有其他选项吗?

2个回答

4

您可以使用clojure.walk/postwalk。简单版本不区分地图中的关键字是键还是值,只是将所有键转换为字符串:

(def data {:person/name "Kevin"
           :person/age 99
           :person/gender :gender/M
           :person/address {:address/state :state/NY
                            :address/city "New York"
                            :address/zip "99999"}})


(clojure.walk/postwalk
  (fn [x]
    (if (keyword? x)
      (name x)
      x))
  data)

;; => => {"name" "Kevin", "age" 99, "gender" "M", "address" {"state" "NY", "city" "New York", "zip" "99999"}}

要实现您想要的功能,需要分别处理映射中的键和值:

(defn transform-keywords [m]
  (into {}
        (map (fn [[k v]]
               (let [k (if (keyword? k) (keyword (name k)) k)
                     v (if (keyword? v) (name v) v)]
                 [k v]))
             m)))

(clojure.walk/postwalk
  (fn [x]
    (if (map? x)
      (transform-keywords x)
      x))
  data)

;; => => {:name "Kevin", :age 99, :gender "M", :address {:state "NY", :city "New York", :zip "99999"}}

3
作为一则附注:根据我的经验,在系统边界处,命名空间限定和非命名空间限定键之间的阻抗不匹配可能会持续成为一个问题;而且,使用命名空间限定键在代码清晰度方面具有显著优势(非常好的数据可追溯性)。
因此,我不会轻易放弃命名空间限定键。如果EDN用于命名空间的语法(带有点和斜杠)不适合您的API消费者,甚至可以使用更常规的下划线(例如:person_name而不是:person/name);这样做可能会更加丑陋,但它仍然给您提供了大部分命名空间限定键的好处,您甚至不需要转换数据结构,而Datomic也不会介意。

我同意这个观点,尽管前端工程师可能会觉得在JSON键中使用斜杠很烦人。我只是在玩弄datomic,所以无论如何都不太重要,但感谢提供替代观点。 - Kevin
是的,这就是为什么我建议使用另一种语法。 - Valentin Waeselynck

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接