我有一个疯狂的想法,包括将一些clojure代码放入CouchDB并编写查询它的视图。我不想将clojure代码存储为纯文本,因为那时我不得不担心在视图中解析它。不需要保留格式和注释,但代码应该能够在不改变结构的情况下进出数据库。关键字,符号和字符串都应保留其原生类型。此外,我希望代码看起来更优雅,更高效。
我正在考虑如下代表事项:
赞赏批评,经验和想法。
编辑:如果我尝试使用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"]]]
上面的第4行需要完成的工作与第2行完全相同。看来它是一个库项目,除非在某个地方有一个我不知道的功能。< / p>
有了这样的库,这就是调用它的样子:
user> (= (json-to-code (read-json (json-str (code-to-json code)))) code)
true
答案 0 :(得分:9)
正如迈克拉所建议的,clojure.contrib.json / write-json不仅会转换原始类型,还会转换Clojure的ISeq
和Java的Map
s,Collection
和{{1也是。这应该涵盖你的大部分代码(被视为数据),但是如果你想写任何更好的东西,通过模仿Stuart Sierra的源代码(参见here),可以很容易地扩展JSON编写器:
Array
这假设您不需要存储计算字节码或捕获的闭包。这将是一个完全不同的游戏,更加困难。但由于大多数Clojure代码(如大多数Lisp代码)可以被视为S-Expressions的树/林,你应该没问题。
可以使用(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})
将JSON解析回数据(花一点时间查看其定义中的选项,您可能想要使用它们)。在此之后,clojure.contrib.json/read-json
可能是您最好的朋友。
答案 1 :(得分:8)
如果你想使用JSON作为表示,我强烈建议使用clojure.contrib.json,它已经完成了将Clojure数据结构无缝转换为JSON的工作。
没有必要重新发明轮子: - )
我在目前的Clojure项目中使用得非常成功。如果它没有做你想做的一切,那么你总是可以提供补丁来改进它!
答案 2 :(得分:7)
我认为您的想法很合理,但我通过使用标记数组(["list", …]
,["vector", …]
)来简化对集合的处理。除此之外,我不会改变实施策略。
我喜欢你的想法并在Clojure中编码,因此我在https://gist.github.com/3219854处实施了code-to-json
(包含上述建议)。
这是它产生的输出:
(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"]]]
json-to-code
留给读者练习。 ;)
答案 3 :(得分: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}
您可能还想使用cheshire
,它具有良好的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}
答案 4 :(得分:4)
为了完整起见,还有clj-json使用Jackson来解析JSON。
答案 5 :(得分:0)
对于 clojure.data.json 的0.1.2版,整个事情看起来像是这样我猜:
(require ['clojure.data.json :as 'json])
(defn- json-write-date [s ^java.io.PrintWriter out escape-unicode?]
(.write out (str "\""
(.format (java.text.SimpleDateFormat. "yyyyMMddHHmmssZ") s) "\"")))
(extend java.util.Date clojure.data.json/Write-JSON {:write-json json-write-date})
(json/json-str { :example (java.util.Date.)})
"{\"example\":\"20120318182612+0100\"}"`