Skip to content

timmc/enlive

 
 

Repository files navigation

Enlive

Enlive is a selector-based (à la CSS) templating library for Clojure.

An Enlive template has two parts: a HTML file and a deftemplate form somewhere in a clj file.

David Nolen wrote a nice tutorial
Another tutorial by Brian Marick.

Where do I get support?

On the group

What’s new in Enlive?

(most recent first)

Binding *xml-style-self-close* to false while realizing an emitted markup
sequence will use HTML-style slash-less self-closing tags, e.g. <img>
instead of <img/>.

Example:

  (let [f (java.io.File. "some/example/file.html")]
    (binding [*xml-style-self-close* false]
      (apply str (emit* (html-resource f)))))

By default selector-transformation pairs are run sequentially. When you know
that several transformations are independent, you can now specify (as an
optimization) to process them in lockstep. Note that this doesn’t work with
fragments selectors.

Example:

  [:a :selector] a-transformation
  [:another :selector] another-transformation
  [:a :dependent :selector] yet-another-transformation

If the first two tarnsformations are independent you can rewrite this code as:

  :lockstep
  {[:a :selector] a-transformation
   [:another :selector] another-transformation}
  [:a :dependent :selector] yet-another-transformation

Transformations are now slightly restricted in their return values: a node or
a collection of nodes (instead of freely nested collections of nodes).

Dynamic selectors: selectors aren’t compiled anymore. It means that you don’t
need to wrap them in (selector …) forms anymore nor to eval thme in the most
dynamic cases.

Fragment selectors allow to select adjacent nodes. They are denoted by a map of
two node selectors (eg {[:h1] [:p]}), bounds are inclusive and they select
the smallest matching fragments.

Transformations (the right-hand parts of rules) are now plain old closures.
These functions take one arg (the selected node) and return nil, another node
or a collection of nodes.

Rules are applied top-down: the first rule transforms the whole tree and the
resulting tree is passed to the next rules.

Nodes are transformed deep-first, that is: if a selector selects several nodes,
descendants are transformed first. Hence, when the transformation is applied to
an ancestor, you can “see” the transformed descendants (but you can not see
your transformed siblings).

   /B                                                                             /(T B)
  A    if A and B are selected and transformed by T the the resulting tree is (T A      )
   \C                                                                             \C

Templates and snippets

A snippet is a function that returns a seq of nodes, it can be used as a
building block for more complex templates.

A template is a function that returns a seq of string — basically it’s a
snippet whose output is serialized. Templates return a seq of strings to avoid
building the whole string.

Templates and snippets transform a source (specified as a path (to access
resources on the classpath), a File, a Reader, an InputStream, an URI, an URL,
an element or a seq of nodes).

The at form

The at form is the most important form in Enlive. There are implicit at
forms in snippet and template.

  (at a-node
    [:a :selector] a-transformation
    [:another :selector] another-transformation
    ...)

The right-hand value of a rule can be nil. It’s the idiomatic way to remove an
element.

Transformations are closures which take one arg (the selected node) and return
nil, another node or an arbitrarily nested collection of nodes.

Rules are applied top-down: the first rule transforms the whole tree and the
resulting tree is passed to the next rules.

Selectors

Enlive selectors can match either nodes or fragments (several adjacent nodes).

Syntax

See syntax.html

Some examples:

  Enlive                           CSS
  =======================================================
  [:div]                                       div
  [:body :script]                              body script
  #{[:ul.outline :> :li] [:ol.outline :> li]}  ul.outline > li, ol.outline > li 
  [#{:ul.outline :ol.outline} :> :li]          ul.outline > li, ol.outline > li
  [[#{:ul :ol} :.outline] :> :li]              ul.outline > li, ol.outline > li
  [:div :> :*]                                 div > *
  [:div :> text-node]                          (text children of a div) 
  [:div :> any-node]                           (all children (including text nodes and comments) of a div)
  {[:dt] [:dl]}                                (fragments starting by DT and ending at the *next* DD)    

Transformations

A transformation is a function that returns either a node or collection of node.

Enlive defines several helper functions:


content (content “xyz” a-node “abc”)
html-content (html-content “please no”)
wrap (wrap :div) or (wrap :div {:class "foo"})
unwrap unwrap
set-attr (set-attr :attr1 “val1” :attr2 “val2”)
remove-attr (remove-attr :attr1 :attr2)
add-class (add-class “foo” “bar”)
remove-class (remove-class “foo” “bar”)
do→ (do→ transformation1 transformation2)
clone-for (clone-for [item items] transformation)
or (clone-for [item items]
selector1 transformation1
selector2 transformation2)
append (append “xyz” a-node “abc”)
prepend (prepend “xyz” a-node “abc”)
after (after “xyz” a-node “abc”)
before (before “xyz” a-node “abc”)
substitute (substitute “xyz” a-node “abc”)
move (move [:.footnote] [:#footnotes] content)

Known limitations/problems

  • No namespaces support (hence unsuitable for most XML)

About

a selector-based (à la CSS) templating and transformation system for Clojure

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Clojure 100.0%