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

时间:2021-03-05 22:52:57

I have a crazy idea, which involves putting some clojure code into CouchDB and writing views that query it. I don't want to store the clojure code as plain text, because then I would have to worry about parsing it in the views. Formatting and comments don't need to be preserved, but the code should be able to go in and out of the database without changing in structure. Keywords, symbols, and strings should all stay in their native type. Additionally, I want the code to look elegant and be efficient.

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

I'm thinking of representing things as follows:

我想把事情表示如下:

  • Symbols as strings that start with '
  • 符号为以''开头的字符串
  • Keywords as strings that start with :
  • 作为字符串开头的关键字:
  • Strings unmodified, except when they start with ' or :, in which case they're escaped with a backslash.
  • 字符串未经修改,除非它们以'或:开头,在这种情况下,它们使用反斜杠进行转义。
  • (parens) as an array
  • (parens)作为一个数组
  • [brackets] as an array with "_[]" as the first element
  • [括号]为数组,以“_ []”作为第一个元素
  • maps ({}) as an object
  • maps({})作为对象
  • sets (#{}) as an object with the values set to 1 and "_#{}" included.
  • 将(#{})设置为包含值设置为1和“_#{}”的对象。

Critiques, experiences, and ideas are appreciated.

赞赏批评,经验和想法。

Edit: Here's what happens if I try reading and writing JSON code using json functions from clojure.contrib:

编辑:如果我尝试使用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"]]]

There's a fair bit that needs to be done for line 4 of the above to be exactly like line 2. It appears that it's a library project, unless there's a function somewhere that does it that I don't know about.

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

With such a library, here's what calling it might look like:

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

user> (= (json-to-code (read-json (json-str (code-to-json code)))) code)
true

6 个解决方案

#1


7  

I think your idea is sound, but I'd simplify the handling of collections by using tagged arrays (["list", …], ["vector", …]) instead. Apart from that, I wouldn't change the implementation strategy.

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

I like your idea and to code in Clojure, so I took a stab at implementing your code-to-json (with the above suggestion incorporated) at https://gist.github.com/3219854.

我喜欢你的想法并在Clojure中编写代码,所以我在https://gist.github.com/3219854上实现了你的code-to-json(包含上面的建议)。

This is the output it generates:

这是它生成的输出:

(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 is left as an exercise for the reader. ;)

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

#2


9  

As mikera suggested, clojure.contrib.json/write-json will convert not only primitive types, but Clojure's ISeqs and Java's Maps, Collections and Arrays, too. This should cover most of your code (seen as data), but in the event you want to write anything fancier, it's easy to extend the JSON writer, by mimicking out Stuart Sierra's source code (see here):

正如迈克拉所建议的那样,clojure.contrib.json / write-json不仅会转换原始类型,还会转换Clojure的ISeqs和Java的地图,集合和数组。这应该涵盖你的大多数代码(被视为数据),但是如果你想写任何更好的东西,通过模仿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})

This is assuming you don't need to store computed bytecode, or captured closures. This would be an entirely different game, significantly harder. But since most Clojure code (like most Lisp's) can be seen as a tree/forest of S-Expressions, you should be OK.

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

Parsing out JSON back to the data can be done with clojure.contrib.json/read-json (take a short time to look at the options on its definition, you may want to use them). After that, eval may be your best friend.

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

#3


8  

If you want to use JSON as a representation, I'd strongly suggest using clojure.contrib.json, which already does the job of converting Clojure data structures to JSON pretty seamlessly.

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

No point reinventing the wheel :-)

没有必要重新发明*:-)

I've used it pretty successfully in my current Clojure project. If it doesn't do everything you want, then you can always contribute a patch to improve it!

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

#4


5  

clojure.contrib.json has been superseded by clojure.data.json:

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}

You might also like to use cheshire which has a nice API and support for various extensions such as custom encoding and SMILE (binary JSON):

您可能还想使用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}

#5


4  

For completeness sake there is also clj-json which uses Jackson underneath to parse the JSON.

为了完整起见,还有clj-json使用Jackson来解析JSON。

#6


0  

With version 0.1.2 of clojure.data.json the whole thing could look like this I guess:

使用版本0.1.2的clojure.data.json,整个事情看起来像我猜:

(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\"}"`

#1


7  

I think your idea is sound, but I'd simplify the handling of collections by using tagged arrays (["list", …], ["vector", …]) instead. Apart from that, I wouldn't change the implementation strategy.

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

I like your idea and to code in Clojure, so I took a stab at implementing your code-to-json (with the above suggestion incorporated) at https://gist.github.com/3219854.

我喜欢你的想法并在Clojure中编写代码,所以我在https://gist.github.com/3219854上实现了你的code-to-json(包含上面的建议)。

This is the output it generates:

这是它生成的输出:

(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 is left as an exercise for the reader. ;)

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

#2


9  

As mikera suggested, clojure.contrib.json/write-json will convert not only primitive types, but Clojure's ISeqs and Java's Maps, Collections and Arrays, too. This should cover most of your code (seen as data), but in the event you want to write anything fancier, it's easy to extend the JSON writer, by mimicking out Stuart Sierra's source code (see here):

正如迈克拉所建议的那样,clojure.contrib.json / write-json不仅会转换原始类型,还会转换Clojure的ISeqs和Java的地图,集合和数组。这应该涵盖你的大多数代码(被视为数据),但是如果你想写任何更好的东西,通过模仿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})

This is assuming you don't need to store computed bytecode, or captured closures. This would be an entirely different game, significantly harder. But since most Clojure code (like most Lisp's) can be seen as a tree/forest of S-Expressions, you should be OK.

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

Parsing out JSON back to the data can be done with clojure.contrib.json/read-json (take a short time to look at the options on its definition, you may want to use them). After that, eval may be your best friend.

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

#3


8  

If you want to use JSON as a representation, I'd strongly suggest using clojure.contrib.json, which already does the job of converting Clojure data structures to JSON pretty seamlessly.

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

No point reinventing the wheel :-)

没有必要重新发明*:-)

I've used it pretty successfully in my current Clojure project. If it doesn't do everything you want, then you can always contribute a patch to improve it!

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

#4


5  

clojure.contrib.json has been superseded by clojure.data.json:

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}

You might also like to use cheshire which has a nice API and support for various extensions such as custom encoding and SMILE (binary JSON):

您可能还想使用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}

#5


4  

For completeness sake there is also clj-json which uses Jackson underneath to parse the JSON.

为了完整起见,还有clj-json使用Jackson来解析JSON。

#6


0  

With version 0.1.2 of clojure.data.json the whole thing could look like this I guess:

使用版本0.1.2的clojure.data.json,整个事情看起来像我猜:

(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\"}"`