如何在JSON之间映射clojure代码?
我有一个疯狂的想法,它涉及到将一些clojure代码放入CouchDB并编写查询它的视图。我不想将clojure代码存储为纯文本,因为这样我就不得不担心在视图中解析它。格式和注释不需要保留,但是代码应该能够在不改变结构的情况下进出数据库。关键字、符号和字符串都应保持其本机类型。此外,我希望代码看起来优雅高效 我想把事情表现如下:如何在JSON之间映射clojure代码?,json,clojure,lisp,couchdb,Json,Clojure,Lisp,Couchdb,我有一个疯狂的想法,它涉及到将一些clojure代码放入CouchDB并编写查询它的视图。我不想将clojure代码存储为纯文本,因为这样我就不得不担心在视图中解析它。格式和注释不需要保留,但是代码应该能够在不改变结构的情况下进出数据库。关键字、符号和字符串都应保持其本机类型。此外,我希望代码看起来优雅高效 我想把事情表现如下: 以' 以以下字符串开头的关键字: 字符串未经修改,除非它们以“或:”开头,在这种情况下,它们用反斜杠转义 (parens)作为数组 [括号]作为第一个元素为“[]”的
- 以'
- 以以下字符串开头的关键字:
- 字符串未经修改,除非它们以“或:”开头,在这种情况下,它们用反斜杠转义
- (parens)作为数组
- [括号]作为第一个元素为“[]”的数组
- 将({})映射为对象
- 将(#{})设置为对象,其值设置为1并包含“#{}”
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行完全一样,还需要做很多工作。这似乎是一个库项目,除非某个地方有一个我不知道的函数
有了这样一个库,调用它可能是这样的:
user> (= (json-to-code (read-json (json-str (code-to-json code)))) code)
true
如果您想使用JSON作为表示,我强烈建议使用,它已经完成了将Clojure数据结构无缝转换为JSON的工作 没有必要重新发明轮子:-) 我在当前的Clojure项目中非常成功地使用了它。如果它不能做到你想要的一切,那么你可以随时贡献一个补丁来改进它 正如mikera所建议的,/write json不仅会转换原始类型,还会转换Clojure的
ISeq
s和Java的Map
s、Collection
s和Array
s。这应该涵盖您的大部分代码(视为数据),但如果您想编写更高级的代码,可以通过模仿Stuart Sierra的源代码来扩展JSON编写器(请参阅):
这是假设您不需要存储计算字节码或捕获的闭包。这将是一场完全不同的游戏,难度要大得多。但是,由于大多数Clojure代码(像大多数Lisp代码一样)都可以被视为一棵树/森林,所以您应该可以
可以使用
clojure.contrib.JSON/read JSON
将JSON解析回数据(花一点时间查看其定义上的选项,您可能需要使用它们)。在那之后,eval
可能是你最好的朋友。为了完整起见,还有一个在下面使用Jackson解析JSON的工具。对于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\"}"`
我认为你的想法是正确的,但我会通过使用标记数组(
[“list”,…]
,[“vector”,…]
)来简化集合的处理。除此之外,我不会改变实施策略
我喜欢你的想法,也喜欢用Clojure编写代码,所以我尝试了一下将你的代码实现为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
留给读者作为练习 clojure.contrib.json
已被以下内容取代:
您可能还想使用它,它有一个很好的API,并支持各种扩展,如自定义编码和SMILE(二进制JSON):
我不打算为json编写解析器,所以我可能会使用clojure.contrib.json。我正在寻找一种方法,将任意clojure代码映射到一个足够简单的数据结构中,并从中无损地转换为JSON。我想将这个问题标记为已回答,但到目前为止的答案确实没有涵盖它!我正在寻找一个示例,说明如何反序列化为JSON,同时保留Clojure读者理解的类型。这需要元数据。如果您只是在为Clojure寻找基本的JSON序列化程序/反序列化程序,那么很抱歉您会看到此页面。这不是这个问题的重点。这实际上不起作用,因为“编写json字符串”是一个私有函数。您可以做的是:(defn-write json奇特类型[x#^PrintWriter out](.print out(json str(str x)))确切地说,它是一个私有函数,应该定义它来编写一些有用的东西,比如您提到的.print。我指的不是库中的某个特定函数-很抱歉,最终会出现误导。我希望您注意细节。:)对我来说似乎很健壮。
(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"]]]
(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}
(: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}