如何将clojure代码映射到JSON和从JSON映射?

Ben*_*kin 22 lisp json couchdb clojure

我有一个疯狂的想法,其中包括将一些clojure代码放入CouchDB并编写查询它的视图.我不想将clojure代码存储为纯文本,因为那时我不得不担心在视图中解析它.不需要保留格式和注释,但代码应该能够在不改变结构的情况下进出数据库.关键字,符号和字符串都应保留其原生类型.此外,我希望代码看起来优雅,高效.

我想把事情表示如下:

  • 符号为以''开头的字符串
  • 作为字符串开头的关键字:
  • 字符串未经修改,除非它们以'或:开头,在这种情况下,它们会以反斜杠进行转义.
  • (parens)作为一个数组
  • [括号]为数组,以"_ []"作为第一个元素
  • maps({})作为对象
  • 将(#{})设置为包含值设置为1和"_#{}"的对象.

赞赏批评,经验和想法.

编辑:如果我尝试使用clojure.contrib中的json函数读取和编写JSON代码,会发生什么:

user> code
((ns bz.json.app (:use (ring.middleware file))) (defn hello [req] {:status 200, :headers {"Content-Type" "text/plain"}, :body "Hello World!"}) (def app (wrap-file hello "public")))
user> (read-json (json-str code))
[["ns" "bz.json.app" ["use" ["ring.middleware" "file"]]] ["defn" "hello" ["req"] {"body" "Hello World!", "headers" {"Content-Type" "text/plain"}, "status" 200}] ["def" "app" ["wrap-file" "hello" "public"]]]
Run Code Online (Sandbox Code Playgroud)

对于上面的第4行,有一点需要完成,就像第2行一样.看起来它是一个库项目,除非在某个地方有一个我不知道的功能.

有了这样的库,这就是调用它的样子:

user> (= (json-to-code (read-json (json-str (code-to-json code)))) code)
true
Run Code Online (Sandbox Code Playgroud)

Edg*_*gar 9

正如迈克拉所建议的那样,clojure.contrib.json/write-json不仅会转换原始类型,还会转换Clojure的ISeqs和Java的Maps,Collections和Arrays.这应该涵盖你的大多数代码(被视为数据),但是如果你想写任何更好的东西,通过模仿Stuart Sierra的源代码(参见这里),可以很容易地扩展JSON编写器:

(defn- write-json-fancy-type [x #^PrintWriter out]
    (write-json-string (str x) out)) ;; or something useful here!

(extend your-namespace.FancyType clojure.contrib.json/Write-JSON
    {:write-json write-json-fancy-type})
Run Code Online (Sandbox Code Playgroud)

这假设您不需要存储计算字节码或捕获的闭包.这将是一个完全不同的游戏,更加困难.但是,由于大多数Clojure代码(像大多数Lisp一样)可以被视为S-Expressions的树/林,你应该没问题.

将JSON解析回数据可以完成clojure.contrib.json/read-json(花一点时间查看其定义中的选项,您可能想要使用它们).在那之后,eval可能是你最好的朋友.


mik*_*era 8

如果你想使用JSON作为表示,我强烈建议使用clojure.contrib.json,它已经完成了将Clojure数据结构无缝转换为JSON的工作.

没有必要重新发明轮子:-)

我在目前的Clojure项目中使用得非常成功.如果它没有做你想要的一切,那么你总是可以提供补丁来改善它!


qer*_*rub 7

我认为你的想法很合理,但我会通过使用标记数组(["list", …],["vector", …])来简化集合的处理.除此之外,我不会改变实施策略.

我喜欢你的想法并在Clojure中编码,所以我code-to-jsonhttps://gist.github.com/3219854上实施了你的(通过上述建议).

这是它生成的输出:

(code-to-json example-code)
; => ["list" ["list" "'ns" "'bz.json.app" ["list" ":use" ["list" "'ring.middleware" "'file"]]] ["list" "'defn" "'hello" ["vector" "'req"] {":status" 200, ":headers" {"Content-Type" "text/plain"}, ":body" "Hello World!"}] ["list" "'def" "'app" ["list" "'wrap-file" "'hello" "public"]]]
Run Code Online (Sandbox Code Playgroud)

json-to-code留给读者的练习.;)


Dre*_*kes 5

clojure.contrib.json已取代clojure.data.json:

(require '[clojure.data.json :as json])

(json/write-str {:a 1 :b 2})
;;=> "{\"a\":1,\"b\":2}"

(json/read-str "{\"a\":1,\"b\":2}")
;;=> {"a" 1, "b" 2}
Run Code Online (Sandbox Code Playgroud)

您可能还想使用cheshire哪个API具有良好的API并支持各种扩展,例如自定义编码和SMILE(二进制JSON):

(:require [cheshire.core :as json])

(json/encode {:a 1 :b 2})
;;=> "{\"a\":1,\"b\":2}"

(json/decode "{\"a\":1,\"b\":2}")
;;=> {"a" 1, "b" 2}
Run Code Online (Sandbox Code Playgroud)