clojure zippers with hiccup and mongodb



This post deals with how to deserialize Hiccup content from a Clojure Vector stored in MongoDB. I ran into this problem while rewriting my site. The Monger driver offers some great functions to make Mongo easy to use with Clojure but I needed to write some additional logic to get the behavior I wanted. Over the course of the post we will be dealing with three libraries:

MongerThe standard MongoDB library for Clojure.
HiccupThe standard HTML templating library for Clojure.
Clojure ZipClojure's supplied tree traversal and modification library.


We will use a simple leinigen project with 2 files to follow through this post. We are assuming Mongo is installed on the box. So first off create the project as below.

Then copy the details below into the project file. This will provide the dependencies for the example.

the problem

When rewriting my site I wanted to be able to add new blog postings without redeploying the app. To do this I thought I would store the Hiccup representing a post in Mongo along with its tags etc and have the site read its blog data straight from the DB. This turned out to be quite simple but I ran into a small hitch deserializing the Hiccup back out of Mongo. The easiest way to demonstrate this is with an example.

Paste this code into the core.clj file and we will run through it in a REPL session.

Using these functions in a REPL session we can see that the Hiccup that is read back from Mongo no longer has a keyword as the head of each vector. Instead it has been replaced by a plain string.

the solution - clojure zippers

To navigate the Hiccup tree and update the leading element of each vector to a keyword we are going to use Clojure Zippers. They allow us to navigate and edit the tree in a functional fashion.

Paste the 2 functions below into core.clj and reload the namespace.

Running the deserialization function in our REPL against the results from the Mongo we can see the Hiccup is now being returned in the same format as when it was inserted.