代码之家  ›  专栏  ›  技术社区  ›  Benjamin Atkin

如何将clojure代码与JSON进行映射?

  •  22
  • Benjamin Atkin  · 技术社区  · 14 年前

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

    我想用下面的方式来表示:

    • 以“”开头的字符串形式的符号
    • 关键字作为以以下开头的字符串:
    • 字符串未被修改,除非它们以'或:'开头,在这种情况下,它们用反斜杠转义。
    • (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"]]]
    

    有了这样一个库,调用它可能是这样的:

    user> (= (json-to-code (read-json (json-str (code-to-json code)))) code)
    true
    
    6 回复  |  直到 14 年前
        1
  •  7
  •   qerub    12 年前

    我认为你的想法是正确的,但是我会通过使用标记数组来简化集合的处理( ["list", …] , ["vector", …]

    code-to-json (包含上述建议)在 https://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"]]]
    

    json-to-code 留给读者做练习

        2
  •  10
  •   Edgar Gonçalves    14 年前

    正如米凯拉所说, clojure.contrib.json /write-json不仅可以转换原语类型,还可以转换Clojure的 ISeq s和Java Map 是的, Collection s和 Array s、 我也是。这应该涵盖大部分代码(被视为数据),但是如果您想编写更高级的代码,可以通过模仿Stuart Sierra的源代码来扩展JSON编写器(请参阅 here ):

    (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})
    

    这是假设您不需要存储计算的字节码或捕获的闭包。这将是一场完全不同的比赛,难度很大。但是由于大多数Clojure代码(像大多数Lisp)都可以看作是 S-Expressions ,你应该没事。

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

        3
  •  9
  •   mikera    14 年前

    clojure.contrib.json ,它已经完成了将Clojure数据结构无缝地转换为JSON的工作。

    我在当前的Clojure项目中已经非常成功地使用了它。如果它不能做到你想要的一切,那么你可以随时贡献一个补丁来改进它!

        4
  •  5
  •   Drew Noakes    11 年前

    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}
    
        5
  •  4
  •   kotarak    14 年前

    为了完整起见,还有 clj-json

        6
  •  1
  •   Benjamin Peter    12 年前

    版本为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\"}"`