· clojure

Clojure: Writing JSON to a file/reading JSON from a file

A few weeks ago I described how I’d scraped football matches using Clojure’s Enlive, and the next step after translating the HTML representation into a Clojure map was to save it as a JSON document.

I decided to follow a two step process to achieve this:

  • Convert hash to JSON string

  • Write JSON string to file

I imagine there’s probably a way to convert the hash to a stream and pipe that into a file but my JSON document isn’t very large so I think this way is ok for now.

https://github.com/clojure/data.json seems to be the way to go to convert a Hash to a JSON string and I had the following code:

> (require '[clojure.data.json :as json])
nil

> (json/write-str { :key1 "val1" :key2 "val2" })
"{\"key2\":\"val2\",\"key1\":\"val1\"}"

The next step was to write that into a file and this StackOverflow post describes a couple of ways that we can do this:

> (use 'clojure.java.io)
> (with-open [wrtr (writer "/tmp/test.json")]
    (.write wrtr (json/write-str {:key1 "val1" :key2 "val2"})))

or

> (spit "/tmp/test.json" (json/write-str {:key1 "val1" :key2 "val2"}))

Now I wanted to read the file back into a hash and I started with the following:

> (json/read-str (slurp "/tmp/test.json"))
{"key2" "val2", "key1" "val1"}

That’s not bad but I wanted the keys to be what I know as symbols (e.g. ':key1') from Ruby land. I re-learnt that this is called a keyword in Clojure.

Since I’m not very good at reading the documentation I wrote a function to convert all the keys in a map from strings to keywords:

> (defn string-keys-to-symbols [map]
    (reduce #(assoc %1 (-> (key %2) keyword) (val %2)) {} map))

> (string-keys-to-symbols (json/read-str (slurp "/tmp/test.json")))
{:key1 "val1", :key2 "val2"}

What I should have done is pass the http://clojuredocs.org/clojure_core/clojure.core/keyword function as an argument to read-str instead:

> (json/read-str (slurp "/tmp/test.json") :key-fn keyword)
{:key2 "val2", :key1 "val1"}

Simple!

  • LinkedIn
  • Tumblr
  • Reddit
  • Google+
  • Pinterest
  • Pocket