Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Clojure: Writing JSON to a File/Reading JSON From a File

DZone's Guide to

Clojure: Writing JSON to a File/Reading JSON From a File

· Java Zone ·
Free Resource

The CMS developers love. Open Source, API-first and Enterprise-grade. Try BloomReach CMS for free.

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.

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 keyword function as an argument to read-str instead:

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

Simple!

BloomReach CMS: the API-first CMS of the future. Open-source & enterprise-grade. - As a Java developer, you will feel at home using Maven builds and your favorite IDE (e.g. Eclipse or IntelliJ) and continuous integration server (e.g. Jenkins). Manage your Java objects using Spring Framework, write your templates in JSP or Freemarker. Try for free.

Topics:

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}