Enlive is a Clojure library for generating HTML that uses transformations instead of templates. Rather than starting with templates containing code which are then executed to produce the final output, it starts with plain HTML which is subjected to a series of transformations; the transformations are ordinary functions, targeted to the right part of the DOM by standard CSS selectors.
This approach allows a clean separation between template and code; it avoids creating a novel hybrid language—often crippled and always nasty—for the templates.
As you can tell, I am pretty sold on the benefits of selector-based templating, so I was excited to come across Enlive when I started playing with Clojure. Enlive is powerful and somewhat complex; there are two good tutorials but I found it hard to get straight in my head which bits were really necessary to do something simple.
So, having wrestled with this for a while (and having surface after a longish dive in the Enlive source code), I’ve put together a basic example, which I think takes a reasonable, minimal approach to using Enlive for a simple web application. This post walks through it, explaining how it fits together. It is not intended to be a complete introduction to what Enlive can do; for that, read the tutorials and documentation.
When using Enlive, it’s helpful to know that the library generally uses an internal data structure representation of HTML (called nodes in the documentation). Most functions and macros operate on and return nodes, or collections of them; a few return strings, which you need in order to render the HTML to the outside world (in my case when defining Compojure routes).
The simplest thing we can do is read in an HTML file from disk with
This returns nodes, which can be rendered into strings with
We would also like to be able to show dynamic content. With a
transformation-based approach, we start with static HTML and apply
transformations to it. We’re going to create a
<ul>, with one
for each item in a list. The initial HTML shows the structure we want,
with dummy content in the
1 2 3
Again we read in the HTML using
html-resource, but this time we use
at to apply a transformation.
1 2 3
This targets the
<li> element and applies a transformation which,
for every element in the argument list
things, clones the
fills in its content.
at returns nodes, so we can render the
1 2 3 4 5
(Enlive has a
defsnippet macro which we could use here, but it
doesn’t work in quite the way that we need.)
For a real web application, we need a way of applying common layout and styling to the pages. With Enlive we can use a further transformation to insert the pages that we have so far into a common piece of wrapper HTML.
1 2 3 4 5 6 7 8 9 10 11 12
Enlive provides a macro
deftemplate that we can use here. It wraps a
couple of the things we’ve seen already (
well as doing the function definition for us.
This replaces the contents of
div.content with the HTML that we pass
deftemplate also handles the call to
emit* for us, so replace
layout when defining our routes.
1 2 3
We can improve
layout to apply consistent titles to each page, by
adding an argument and setting the content of
1 2 3 4 5 6 7
And we add those elements, with placeholders, to the layout HTML.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
There is one wrinkle that I’ve glossed over up to this point. Enlive
uses the wonderful TagSoup to parse HTML (so that you can
use the same transformations on “wild” HTML that you’ve scraped from
the web and which may not be well-formed). Because TagSoup assumes
that it’s dealing with something potentially toxic, and tries to
detoxify it, it adds
<body> tags around any HTML that
you give it. So the DOM returned by
html-resource has these extra
tags which end up wrapping the content in the middle of our webpage.
We need to modify
layout to strip these out.
Here is the complete code, which you can see in a working project here.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18