This will help to clarify what is occurring. We start off by including a helpful library:
(ns tst.demo.core
(:use tupelo.core tupelo.test)
(:require
[tupelo.core :as t]
[tupelo.string :as str]
))
In order to avoid the ambiguity of double-quotes for both a literal string and embedded inside of the string, we write the source JSON using single quotes, then use a helper function str/quotes->double to convert every single-quote in the string into a double-quote. Otherwise, we could have read in the source JSON from a file (instead of having it inline).
(def json-str
(str/quotes->double
"{
'Data': [
{
'Metadata': {
'Series': '1/2'
},
'Hybrid': {
'Foo': 76308,
'Bar': '76308',
'Cat': 'Foo123'
}
}
],
'Footer': {
'Count': 3,
'Age': 0
}
} "))
We first convert the json string into an EDN data structure (not a string). We then convert the EDN data struction into an EDN string. The output (both println and prn) illustrate the differences:
(dotest
(let [edn-data (t/json->edn json-str) ; JSON string => EDN data
edn-str (pr-str edn-data) ; EDN data => EDN string
]
(newline)
(println "edn-data =>")
(spy-pretty edn-data) ; uses 'prn'
(newline)
(println "edn-str (println) =>")
(println edn-str)
(newline)
(println "edn-str (prn) =>")
(prn edn-str)))
with result:
------------------------------------------
Clojure 1.10.2-alpha1 Java 14.0.1
------------------------------------------
Testing tst.demo.core
edn-data =>
{:Data
[{:Metadata {:Series "1/2"},
:Hybrid {:Foo 76308, :Bar "76308", :Cat "Foo123"}}],
:Footer {:Count 3, :Age 0}}
edn-str (println) =>
{:Data [{:Metadata {:Series "1/2"}, :Hybrid {:Foo 76308, :Bar "76308", :Cat "Foo123"}}], :Footer {:Count 3, :Age 0}}
edn-str (prn) =>
"{:Data [{:Metadata {:Series \"1/2\"}, :Hybrid {:Foo 76308, :Bar \"76308\", :Cat \"Foo123\"}}], :Footer {:Count 3, :Age 0}}"
Think carefully about what is a data structure and what is a string. If we write [1 :b "hi"] in a Clojure source file, the Clojure Reader creates a data structure that is a 3-element vector containg an int, a keyword, and a string. If we convert that into a string using str, the output is just a string of 11 characters and is not a data structure.
However, if we want to paste that string (inside of double-quotes) into our source file, we need not only the outer double-quotes to mark the beginning and end of the string, but each double-quote inside the string (e.g. as part of the "hi") needs to be escaped, so the Clojure Reader can tell that they belong inside of the string and don't mark the beginning or end of a string.
It takes a while to get used to all of the different modes!
Clojure Reader vs Compiler
Clojure source code files are processed in 2 passes.
The Clojure Reader takes the text of each source file (a giant string of many lines) and converts it into a data structure.
The Clojure Compiler takes the data structure from (1) and outputs Java bytecode.