Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add option to NOT escape Unicode; refs #100 CONTRIB-100
  • Loading branch information
Stuart Sierra committed Nov 30, 2010
1 parent 37fba7e commit 5380552
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 33 deletions.
72 changes: 39 additions & 33 deletions modules/json/src/main/clojure/clojure/contrib/json.clj
Expand Up @@ -199,10 +199,10 @@
;;; JSON PRINTER

(defprotocol Write-JSON
(write-json [object out]
(write-json [object out escape-unicode?]
"Print object to PrintWriter out as JSON"))

(defn- write-json-string [^CharSequence s ^PrintWriter out]
(defn- write-json-string [^CharSequence s ^PrintWriter out escape-unicode?]
(let [sb (StringBuilder. ^Integer (count s))]
(.append sb \")
(dotimes [i (count s)]
Expand All @@ -220,8 +220,11 @@
(= cp 10) (.append sb "\\n")
(= cp 13) (.append sb "\\r")
(= cp 9) (.append sb "\\t")
;; Any other character is Hexadecimal-escaped
:else (.append sb (format "\\u%04x" cp)))))
;; Any other character is Unicode
:else (if escape-unicode?
;; Hexadecimal-escaped
(.append sb (format "\\u%04x" cp))
(.appendCodePoint sb cp)))))
(.append sb \")
(.print out (str sb))))

Expand All @@ -231,49 +234,49 @@
(name x)
(str x)))

(defn- write-json-object [m ^PrintWriter out]
(defn- write-json-object [m ^PrintWriter out escape-unicode?]
(.print out \{)
(loop [x m]
(when (seq m)
(let [[k v] (first x)]
(when (nil? k)
(throw (Exception. "JSON object keys cannot be nil/null")))
(write-json-string (as-str k) out)
(write-json-string (as-str k) out escape-unicode?)
(.print out \:)
(write-json v out))
(write-json v out escape-unicode?))
(let [nxt (next x)]
(when (seq nxt)
(.print out \,)
(recur nxt)))))
(.print out \}))

(defn- write-json-array [s ^PrintWriter out]
(defn- write-json-array [s ^PrintWriter out escape-unicode?]
(.print out \[)
(loop [x s]
(when (seq x)
(let [fst (first x)
nxt (next x)]
(write-json fst out)
(write-json fst out escape-unicode?)
(when (seq nxt)
(.print out \,)
(recur nxt)))))
(.print out \]))

(defn- write-json-bignum [x ^PrintWriter out]
(defn- write-json-bignum [x ^PrintWriter out escape-unicode]
(.print out (str x)))

(defn- write-json-plain [x ^PrintWriter out]
(defn- write-json-plain [x ^PrintWriter out escape-unicode?]
(.print out x))

(defn- write-json-null [x ^PrintWriter out]
(defn- write-json-null [x ^PrintWriter out escape-unicode?]
(.print out "null"))

(defn- write-json-named [x ^PrintWriter out]
(write-json-string (name x) out))
(defn- write-json-named [x ^PrintWriter out escape-unicode?]
(write-json-string (name x) out escape-unicode?))

(defn- write-json-generic [x out]
(defn- write-json-generic [x out escape-unicode?]
(if (.isArray (class x))
(write-json (seq x) out)
(write-json (seq x) out escape-unicode?)
(throw (Exception. (str "Don't know how to write JSON of " (class x))))))

(extend nil Write-JSON
Expand Down Expand Up @@ -301,42 +304,45 @@

(defn json-str
"Converts x to a JSON-formatted string."
[x]
(let [sw (StringWriter.)
[x & options]
(let [{:keys [escape-unicode] :or {escape-unicode true}} options
sw (StringWriter.)
out (PrintWriter. sw)]
(write-json x out)
(write-json x out escape-unicode)
(.toString sw)))

(defn print-json
"Write JSON-formatted output to *out*"
[x]
(write-json x *out*))
[x & options]
(let [{:keys [escape-unicode] :or {escape-unicode true}} options]
(write-json x *out* escape-unicode)))


;;; JSON PRETTY-PRINTER

;; Based on code by Tom Faulhaber

(defn- pprint-json-array [s]
(defn- pprint-json-array [s escape-unicode]
((formatter-out "~<[~;~@{~w~^, ~:_~}~;]~:>") s))

(defn- pprint-json-object [m]
(defn- pprint-json-object [m escape-unicode]
((formatter-out "~<{~;~@{~<~w:~_~w~:>~^, ~_~}~;}~:>")
(for [[k v] m] [(as-str k) v])))

(defn- pprint-json-generic [x]
(defn- pprint-json-generic [x escape-unicode]
(if (.isArray (class x))
(pprint-json-array (seq x))
(print (json-str x))))
(pprint-json-array (seq x) escape-unicode)
(print (json-str x :escape-unicode escape-unicode))))

(defn- pprint-json-dispatch [x]
(defn- pprint-json-dispatch [x escape-unicode]
(cond (nil? x) (print "null")
(instance? java.util.Map x) (pprint-json-object x)
(instance? java.util.Collection x) (pprint-json-array x)
(instance? clojure.lang.ISeq x) (pprint-json-array x)
:else (pprint-json-generic x)))
(instance? java.util.Map x) (pprint-json-object x escape-unicode)
(instance? java.util.Collection x) (pprint-json-array x escape-unicode)
(instance? clojure.lang.ISeq x) (pprint-json-array x escape-unicode)
:else (pprint-json-generic x escape-unicode)))

(defn pprint-json
"Pretty-prints JSON representation of x to *out*"
[x]
(write x :dispatch pprint-json-dispatch))
[x & options]
(let [{:keys [escape-unicode] :or {escape-unicode true}} options]
(write x :dispatch #(pprint-json-dispatch % escape-unicode))))
6 changes: 6 additions & 0 deletions modules/json/src/test/clojure/clojure/contrib/test_json.clj
Expand Up @@ -144,6 +144,9 @@
(deftest can-print-unicode
(is (= "\"\\u1234\\u4567\"" (json-str "\u1234\u4567"))))

(deftest can-print-nonescaped-unicode
(is (= "\"\u1234\u4567\"" (json-str "\u1234\u4567" :escape-unicode false))))

(deftest can-print-json-null
(is (= "null" (json-str nil))))

Expand Down Expand Up @@ -193,3 +196,6 @@
(deftest pretty-printing
(let [x (read-json *pass1-string* false)]
(is (= x (read-json (with-out-str (pprint-json x)) false)))))

(deftest can-pretty-print-nonescaped-unicode
(is (= "\"\u1234\u4567\"" (with-out-str (pprint-json "\u1234\u4567" :escape-unicode false)))))

0 comments on commit 5380552

Please sign in to comment.