Every repository with this icon (
Every repository with this icon (
Getting started
(Original version of this tutorial – Adrian Cuthbertson 2009-04-23 – http://clojure.googlegroups.com/web/enlive-tut1.txt).
Introduction
Enlive is a library for applying clojure based transformations to html documents.
The basic procedure is that you define a template with rules, each having a CSS like selector which selects certain nodes from a parsed html document, and a directive for applying a transformation to the selected node/s in order to create a new output html document.
The Enlive project is hosted at http://github.com/cgrand/enlive.
The project is under active development, so check the latest master branch to work with at the site.
To install…
git clone git://github.com/cgrand/enlive.git
The src directory and lib/tagsoup-1.2.jar are needed on your classpath to use Enlive.
This tutorial conducts a repl session to introduce Enlive’s main features.
Html Source
Lets start with a simple example. Say we have a file t1.html containing…
<html>
<body>
<h1></h1>
</body>
</html>
Exploring what we can do from the repl – start your repl making sure the classpath includes clojure.jar, clojure-contrib.jar, enlive/src, envlive/lib/tagsoup-1.2.jar. Then set your namespace as follows…
user=> (ns x (:refer-clojure :exclude [empty complement]) (:use net.cgrand.enlive-html))
This excludes the clojure/core versions of empty and complement (enlive has it’s own versions), loads enlive-html and sets the ns to x. So, x now contains clojure/core and enlive.
x=> (html-resource "t1.html")
({:tag :html, :attrs nil, :content [{:tag :body, :attrs nil, :content [{:tag :h1, :attrs nil, :content nil}]}]})
From this we see that the html source is parsed from the file into a hash map of nodes representing the structure of the document. Note that html-resource allows you to load source from files, classpath resources, input streams, readers, URL’s etc. Check the source for details.
Here’s another example…
x=> (html-resource (java.io.StringReader. "<html><body><h1></h1></body></html>"))
({:tag :html, :attrs nil, :content [{:tag :body, :attrs nil, :content [{:tag :h1, :attrs nil, :content nil}]}]})
In the deftemplate macro shown below, the html source is determined from the source parameter type, e.g a String implies a file name/path, a Reader implies a Reader source, etc.
Defining Enlive Clojure Templates
Next step is to define a template that will be used to transform the html source…
x=> (deftemplate t1 "t1.html" [] [:html] (content "wargh"))
This says define a template called t1 which transforms source file “t1.html”. We won’t pass any parameters at this stage (hence []). This is followed by the rules for transformation. These comprise one or more selector/directive pairs. In this case, select a node with the tag :html (from the parsed tree described above) and replace it’s content with “wargh”.
x=> t1 #<core$comp__3776$fn__3778 clojure.core$comp__3776$fn__3778@e73e0>
So, t1 has been defined (compiled) as a function
Performing the Transformation
To perform the transformation, call the defined template function (passing parameters if any)…
x=> (apply str (t1)) "<html>wargh</html>"
Why did we use (apply str… ?
x=> (t1)
("<html>" "wargh" "</html>")
Just calling the function performs the transformation, but returns a list of tokens which need to be concatenated into the final output string.
Maybe we actually wanted to set the heading rather than simply replace the :html’s full contents…
x=> (deftemplate t1 "t1.html" [hdr] [:h1] (content hdr)) x=> (apply str (t1 "First Enlive App")) "<html><body><h1>First Enlive App</h1></body></html>"
That’s more likely what we might do, but the two examples illustrate the basic ideas.
A More Elaborate Example
First we need a more elaborate html file (t2.html)…
<html>
<body>
<h1>Sample Header</h1>
<div id="d1">
<p class="d"></p>
</div>
<div id="d2">
<ul class="l">
<li>an item</li>
</ul>
</div>
</body>
</html>
Our goal is to create a Clojure program which will transform this html by…
- Replacing the sample header
- Adding a paragraph to div#d1
- Adding some items to the ul in div#d2
Now the deftemplate…
x=> (deftemplate t2 "t2.html" [hdr para-txt li-itms]
[:h1] (content hdr)
[:div#:d1 :p] (content para-txt)
[:div :ul.l :li] (clone-for [item li-itms] (content item)))
x=> (apply str (t2 "Second Enlive App" "Some paragraph stuff" ["one" "two" "three"]))
"<html><body><h1>Second Enlive App</h1><div id=\"d1\"><p class=\"d\">Some paragraph stuff</p></div><div id=\"d2\">
<ul class=\"l\"><li>one</li><li>two</li><li>three</li></ul></div></body></html>"
Note: The html file must exist before the deftemplate is executed as the compilation (see above) includes parsing the file.
That should get you started with Enlive.
At a Lower Level
The selectors are similar to CSS selectors. Refer to the Enlive project site for a table showing Enlive’s selectors and the equivalent CSS selector.
It’s quite useful while developing with Enlive to try things out at a lower level. The at and sniptest macros can be used for this…
Using at
(def t2-nd (first (html-resource "t2.html")))
That just loads the html and t2-nd now contains the parsed node…
x=> t2-nd
{:tag :html, :attrs nil, :content [{:tag :body, :attrs nil, :content [{:tag :h1, :attrs nil,
:content ["Sample Header"]} {:tag :div, :attrs {:id "d1"}, :content [{:tag :p, :attrs {
:class "d"}, :content nil}]} {:tag :div, :attrs {:id "d2"}, :content [{:tag :ul, :attrs {:class "l"},
:content nil}]}]}]}
Now you can use at to experiment with selectors and transformation directives…
x=> (at t2-nd [:div :ul.l] (content (to-li ["one" "two"])))
({:tag :html, :attrs nil, :content [{:tag :body, :attrs nil, :content [{:tag :h1, :attrs nil,
:content ["Sample Header"]} {:tag :div, :attrs {:id "d1"}, :content [{:tag :p, :attrs {:class "d"},
:content []}]} {:tag :div, :attrs {:id "d2"}, :content [{:tag :ul, :attrs {:class "l"},
:content ({:tag :li, :attrs nil, :content "one"} {:tag :li, :attrs nil, :content "two"})}]}]}]})
Using sniptest
x=> (sniptest "<span>Hello </span>"
[:span] (append "World"))
"<html><body><span>Hello World</span></body></html>"
Transformation Directives
So, every rule has a selector on the left and a transformation directive on the right. The transformation directive is a function that takes one argument (the selected node) and returns a node or sequence of nodes.
Here’s an example…
x=> (at t2-nd [:div :ul.l] (fn [nd] (prn nd) {:tag :huh :attrs {:wah "foo"} :content nil}))
({:tag :ul, :attrs {:class "l"}, :content []}
{:tag :html, :attrs nil, :content [{:tag :body, :attrs nil, :content [{:tag :h1, :attrs nil, :content ["Sample Header"]} {:tag :div, :attrs {:id "d1"}, :content [{:tag :p, :attrs {:class "d"}, :content []}]} {:tag :div, :attrs {:id "d2"}, :content [{:tag :huh, :attrs {:wah "foo"}, :content nil}]}]}]})
There we’re just printing out the selected node, but you could use it in applying the transformation. We’re returning the replacement node as a :huh tag with a :wah attribute with value “foo”.
All that (content x) does is define a function that assocs x into the :content of the passed node.
Here’s it’s definition…
(defn content
"Replaces the content of the node. Values can be nodes or nested collection of nodes."
[& values]
#(assoc % :content (flatten values)))
There are a number of other transformation helper functions in addition to content – wrap, set-attr, remove-attr, etc. Check the source for more info.
This should give you an idea of how powerful Enlive really is and how you could develop sophisticated libraries of selection/transformation functions.
We’ll cover snippets and other more advanced topics in other tutorials.
Summary
Enlive is a powerful html transformation library. It is NOT a templating system in the traditional sense of the word (where code is embedded in html files, e.g JSP, etc).
It is easy to use at a high-level – straight html file transformations, but also has the lower-level features which will allow you to develop very advanced web/content generation applications.
This is functional web development at its best.







