Enlive questions

39 views
Skip to first unread message

Phil Hagelberg

unread,
Mar 18, 2009, 3:47:24 PM3/18/09
to clo...@googlegroups.com

I'm using the Enlive library, and so far I've been pretty impressed. The
way it separates templates out into their own files and doesn't allow
any logic to get mixed up with them is great.

One thing I noticed is that its templates escape all strings passed to
them. In my case I have some strings that are already HTML and don't
need to be escaped; is there any way to skip that?

Also, I keep getting null pointer exceptions when I try to use
deftemplate with a path to an HTML file that isn't on the
classpath. This seems like an odd restriction. Is there a way to use a
file in an arbitrary location as a template?

thanks,
Phil

Tom Hickey

unread,
Mar 18, 2009, 4:32:15 PM3/18/09
to Clojure
Hi Phil,

Regarding your first question, you can use (net.cgrand.enlive-html/
escaped your-string) to skip the escaping of your strings.

Cheers,
Tom

Phil Hagelberg

unread,
Mar 18, 2009, 8:20:03 PM3/18/09
to clo...@googlegroups.com
Tom Hickey <thi...@gmail.com> writes:

> Regarding your first question, you can use (net.cgrand.enlive-html/
> escaped your-string) to skip the escaping of your strings.

Thanks, that's helpful.

I've also noticed one more oddity. Consider this snippet:

(deftemplate index "foo/bar/template.html" [articles]
[:div.articles] (for [{:keys [title content]} articles]
~(at
[:h2] title
[:p.content] (escaped content))))

Applied to this template:

<div class="articles">
<h2></h2>
<p class="content"></p>
</div>

When the thing to insert into the element is just a string (as is the
case with the h2 element), it gets inserted inside the element. But in
the second case, the content paragraph is _replaced_ with the escaped
content rather than putting the escaped content inside the paragraph
tag. So if title had the value "Congratulations" and content had the
value "You win", the final result would be something like:

<h2>Congratulations</h2>
You win

The paragraph node disappears...

From what I can tell the difference seems to be that it goes inside the
node if it's a string, and it replaces the node if it's a function call,
even if the function call results in a string.

This behaviour seems really strange. I feel like maybe there's some
logic I'm missing and that it's not the string/function call difference
that determines replacement vs insertion, but I can't figure out why
it's behaving this way. Would appreciate any explanation.

thanks,
Phil

Christophe Grand

unread,
Mar 19, 2009, 3:17:38 AM3/19/09
to clo...@googlegroups.com
Hi Phil!

Phil Hagelberg a écrit :


> I'm using the Enlive library, and so far I've been pretty impressed. The
> way it separates templates out into their own files and doesn't allow
> any logic to get mixed up with them is great.
>

Thanks for the kind words.

> One thing I noticed is that its templates escape all strings passed to
> them. In my case I have some strings that are already HTML and don't
> need to be escaped; is there any way to skip that?
>

Tom gave you the answer.

> Also, I keep getting null pointer exceptions when I try to use
> deftemplate with a path to an HTML file that isn't on the
> classpath. This seems like an odd restriction. Is there a way to use a
> file in an arbitrary location as a template?
>

You can pass an xml structure to deftemplate instead of the path, it's
the only way to circumvent the classpath at the moment.
I'll look into it.

Christophe

--
Professional: http://cgrand.net/ (fr)
On Clojure: http://clj-me.blogspot.com/ (en)


Christophe Grand

unread,
Mar 19, 2009, 4:16:58 AM3/19/09
to clo...@googlegroups.com
Phil Hagelberg a écrit :

> >From what I can tell the difference seems to be that it goes inside the
> node if it's a string, and it replaces the node if it's a function call,
> even if the function call results in a string.
>
> This behaviour seems really strange. I feel like maybe there's some
> logic I'm missing and that it's not the string/function call difference
> that determines replacement vs insertion, but I can't figure out why
> it's behaving this way. Would appreciate any explanation

I'm not quite happy with this behavior: I wanted to preserve the brevity of setting content from a parameter without resorting to (text my-parameter) but it makes things too irregular.
This "feature" will certainly go away as I'm planning a redesign.

Right now there are several cases:
1/ If the right hand side of a rule is a list and expands to a
template-macro, it is applied without needing to unquote it. The matched
element is replaced by the result of the template-macro.
2/ If the right hand side of a rule is a list and does not expand to a
template-macro, it's random clojure code (which can apply
template-macros on the matched element using unquote). The matched
element is replaced.
3/ Otherwise the right hand side form is implicitly surrounded by the
'text template-macro and go to 1/ ('text replaces the content).


Phil, what's your usecase for inserting raw html, where does it come from?

Thanks,

Phil Hagelberg

unread,
Mar 19, 2009, 12:43:01 PM3/19/09
to clo...@googlegroups.com
Christophe Grand <chris...@cgrand.net> writes:

> I'm not quite happy with this behavior: I wanted to preserve the
> brevity of setting content from a parameter without resorting to (text
> my-parameter) but it makes things too irregular. This "feature" will
> certainly go away as I'm planning a redesign.

Yeah, I'm all for brevity, but it seems that in this case it makes the
rules harder to understand. Please keep the mailing list informed as to
the progress of your redesign.

I notice you use with-test to mix your tests in together with your
implementation. This seems to be less common than storing the tests in
their own file; I'm wondering if you are happy with this approach? One
advantage of keeping things in their own file is that it's easier for
the test suite to serve as a usage example, but keeping it together may
be more convenient for other reasons. I haven't tried it myself.

> Right now there are several cases:
> 1/ If the right hand side of a rule is a list and expands to a
> template-macro, it is applied without needing to unquote it. The matched
> element is replaced by the result of the template-macro.
> 2/ If the right hand side of a rule is a list and does not expand to a
> template-macro, it's random clojure code (which can apply
> template-macros on the matched element using unquote). The matched
> element is replaced.
> 3/ Otherwise the right hand side form is implicitly surrounded by the
> 'text template-macro and go to 1/ ('text replaces the content).

Thanks for explaining.

> > Also, I keep getting null pointer exceptions when I try to use
> > deftemplate with a path to an HTML file that isn't on the
> > classpath. This seems like an odd restriction. Is there a way to use a
> > file in an arbitrary location as a template?
>

> You can pass an xml structure to deftemplate instead of the path, it's
> the only way to circumvent the classpath at the moment.
> I'll look into it.

I can see the benefit of looking on the classpath since it means you can
store your template inside a jar and distribute everything that way. But
I think it would be convenient if it could check for the existence of
the file relative to the current directory first.

> Phil, what's your usecase for inserting raw html, where does it come from?

I'm processing a number of feeds, and I want to output their
contents. But I could think of many others; perhaps people would want to
use an HTML-generating library like Markdown to turn user input into
HTML before inserting it into the template. It's definitely less common
though.

-Phil

Christophe Grand

unread,
Mar 19, 2009, 1:17:11 PM3/19/09
to clo...@googlegroups.com
Phil Hagelberg a écrit :

> I notice you use with-test to mix your tests in together with your
> implementation. This seems to be less common than storing the tests in
> their own file; I'm wondering if you are happy with this approach? One
> advantage of keeping things in their own file is that it's easier for
> the test suite to serve as a usage example, but keeping it together may
> be more convenient for other reasons. I haven't tried it myself.
>

I see two advantages to using with-test:
* documentation/usage examples as you pointed out,
* and that makes me feel guiltier for nor updating them.


> I can see the benefit of looking on the classpath since it means you can
> store your template inside a jar and distribute everything that way. But
> I think it would be convenient if it could check for the existence of
> the file relative to the current directory first.
>

I'll add support for java.io.File and java.net.URL as an argument to
template/deftemplate/snippet/defsnippet in complement of String and xml
tree.

Phil Hagelberg

unread,
Mar 19, 2009, 4:08:39 PM3/19/09
to clo...@googlegroups.com
Christophe Grand <chris...@cgrand.net> writes:

> I see two advantages to using with-test:
> * documentation/usage examples as you pointed out,

Actually I meant that it's nicer for documentation to have the tests in
a separate file since when you're trying to learn how to use the library
initially, you don't care about the implementation. So it's easier to
focus just on the behaviour when you only see the tests before you. But
that's a minor point.

> * and that makes me feel guiltier for nor updating them.

Well that's a downside; if they are stored somewhere else it could be
easier to ignore them. =) Depending on your editing style it may be
annoying if your editor doesn't support having the two files open
side-by-side.

But I did notice you have the use test-is line commented out in the
implementation; it seems a bit unfortunate to have to uncomment that to
run the tests and hope you remember to re-comment it before you commit.

> I'll add support for java.io.File and java.net.URL as an argument to
> template/deftemplate/snippet/defsnippet in complement of String and xml
> tree.

Sounds great; thanks.

-Phil

Christophe Grand

unread,
Mar 20, 2009, 3:59:57 AM3/20/09
to clo...@googlegroups.com
Phil Hagelberg a écrit :

> But I did notice you have the use test-is line commented out in the
> implementation; it seems a bit unfortunate to have to uncomment that to
> run the tests and hope you remember to re-comment it before you commit.
>

The last commit was during the transition to lazy-seq and test-is was
broken.
I'll fix that.

Tom Hickey

unread,
Apr 8, 2009, 5:20:07 PM4/8/09
to Clojure
Hi Christophe,

I keep running into the same problem with elements getting replaced.
I'm trying to set the content of an element with raw html (from a
snippet) and unable to avoid both 1) the html getting escaped and 2)
the element getting replaced. I can avoid one or the other, via
escaped or text, just not both.

I'm looking forward to see what you've got planned for the redesign,
as I'd really like to see this "feature" go away.

Cheers,
Tom

Christophe Grand

unread,
Apr 8, 2009, 8:06:48 PM4/8/09
to clo...@googlegroups.com
Hi Tom,

I'm sorry for this misfeature and, rejoice, it's gone from the ongoing
redesign, there's now an explicit 'content function.
The tildes are gone too!

Christophe


Tom Hickey a écrit :

David Nolen

unread,
Apr 10, 2009, 1:32:50 PM4/10/09
to clo...@googlegroups.com
This is great.  I had thought that supporting some kind of partial template thing would be interesting, but that's actually just my poor logic at work ;)

It seems like with the new version of Enlive I could do something like this:

(deftemplate pageA-template path
  []
  [[:div (attr? :tiptree:replace)]] (fn [xml-node] (find-the-widget-html-file-that-corresponds-to-a-certain-attr-and-return-as-result)))

(deftemplate pageB-template path
  []
  [[:div (attr? :tiptree:replace)]] (fn [xml-node] (find-the-widget-html-file-that-corresponds-to-a-certain-attr-and-return-as-result)))

(def pageAPartial (pageA-template))
(def pageBPartial (pageB-template))

;; the following would work only if templates allowed passing html as strings and not just as files

(deftemplate widgetsPageA pageAPartial
  [map]
  [[:div (attr? :tiptree:widget)]] (fn [xml] (use-xml-attr-and-map-to-apply-and-return-a-snippet))

(deftemplate widgetsPageB pageBPartial
  [map]
  [[:div (attr? :tiptree:widget)]] (fn [xml] (use-xml-attr-and-map-to-apply-and-return-a-snippet))

(def pageA (widgetsPageA someMap))
(def pageB (widgetsPageA someMap))

Considering the above, I'm left wondering if it's possible to further eliminate these redundancies and make templates more reusable. I'm not sure if this is what you had in mind for Enlive, but allowing templates to be created without references to files would make it possible to build very, very composable interfaces.

Of course it's quite possible that you can already do this with Enlive and I'm just unclear about how to accomplish it.

David

David Nolen

unread,
Apr 10, 2009, 1:38:07 PM4/10/09
to clo...@googlegroups.com
Real quick thought:

(deftemplate-generator template-generator
  [args]
  rule-vector transform-fn)

Would produce a template generator.

(def template-name (template-generator path-to-xml-or-file-or-xml-string))

Would produce a real template.

(apply str (template-name arg1 arg2 arg3))

Christophe Grand

unread,
Apr 14, 2009, 9:58:42 AM4/14/09
to clo...@googlegroups.com
Hello David,

David Nolen a écrit :


> Considering the above, I'm left wondering if it's possible to further
> eliminate these redundancies and make templates more reusable. I'm not
> sure if this is what you had in mind for Enlive, but allowing
> templates to be created without references to files would make it
> possible to build very, very composable interfaces.
> Of course it's quite possible that you can already do this with Enlive
> and I'm just unclear about how to accomplish it.

I'm sorry for the lack of documentation.

The "source" of a template/snippet can either be:
- a string (a resource path resolved by the classloader)
- a File, URI or URL,
- a map (a "literal" xml/html tree).

A template is a function that returns a seq of strings. (It's the end of
the "pipeline".)

A snippet is a function that now (in the "new" enlive) returns a seq of
nodes. (I suppose I should add "seq of nodes" as a valid source type.)
Snippets are valid values on the right-hand side of rules. The only
difference between templates and snippets is that templates serialize
their return value.

I suppose you really want to break the computation in two and not write:
(deftemplate pageA-template path
[map]


[[:div (attr? :tiptree:replace)]] (fn [xml-node]
(find-the-widget-html-file-that-corresponds-to-a-certain-attr-and-return-as-result))

[[:div (attr? :tiptree:widget)]] (fn [xml]

(use-xml-attr-and-map-to-apply-and-return-a-snippet)))

or:
(deftemplate pageA-template path
[map]
[[:div (attr? :tiptree:replace)]]
(do->
(fn [xml-node]
(find-the-widget-html-file-that-corresponds-to-a-certain-attr-and-return-as-result))
(fn [xml] (use-xml-attr-and-map-to-apply-and-return-a-snippet))))

(well, it would work if do-> has been ported to the new enlive)

Keeping in mind the difference between a snippet and a template, you
will be able to do what you describe with the new enlive once I
implement 'attr? and add support for seq of nodes as a valid source type.


hth,

Christophe

Christophe Grand

unread,
Apr 14, 2009, 1:31:20 PM4/14/09
to clo...@googlegroups.com
I pushed do->, attr=, attr? and snippets values as source to github
http://github.com/cgrand/enlive/commits/right

Christophe Grand a écrit :

David Nolen

unread,
Apr 14, 2009, 5:09:22 PM4/14/09
to clo...@googlegroups.com
Great! I will play around with the new features and returns with some more informed feedback ;)

David Nolen

unread,
Apr 14, 2009, 11:05:56 PM4/14/09
to clo...@googlegroups.com
One early thought, would you like me to extend the number of examples? I'm really getting into the nitty gritty of what's possible with Enlive and it would be nice to have a relatively informative list of possibilities distributed with the library vs. the single example that's in there right now ;)

Adrian Cuthbertson

unread,
Apr 14, 2009, 11:32:04 PM4/14/09
to clo...@googlegroups.com
I'm just starting out on Enlive - any examples added would be welcome.
I'll also accumulate some documentation as I go through the learning
curve.

Thanks, Adrian.

David Nolen

unread,
Apr 15, 2009, 12:13:54 AM4/15/09
to clo...@googlegroups.com
Sorry to bombard but I couldn't get attr? or attr= to work inside the selector:

(deftemplate my-app4 "app.html"
  [widgets]
  [:div '(attr? :tiptree:replace)] (content "bar"))
(apply str (my-app4 {}))

(deftemplate my-app4 "app.html"
  [widgets]
  [[:div '(attr? :tiptree:replace)]] (content "bar"))
(apply str (my-app4 {}))

Neither forms worked for me. I messed around with the enlive code itself for quite a bit trying to understand what was going on under the hood but to no avail.

Christophe Grand

unread,
Apr 15, 2009, 2:50:36 AM4/15/09
to clo...@googlegroups.com
David Nolen a écrit :

> Sorry to bombard but I couldn't get attr? or attr= to work inside the
> selector:
>
> (deftemplate my-app4 "app.html"
> [widgets]
> [:div '(attr? :tiptree:replace)] (content "bar"))
> (apply str (my-app4 {}))
>
> (deftemplate my-app4 "app.html"
> [widgets]
> [[:div '(attr? :tiptree:replace)]] (content "bar"))
> (apply str (my-app4 {}))
>
> Neither forms worked for me. I messed around with the enlive code
> itself for quite a bit trying to understand what was going on under
> the hood but to no avail.

I'll lift the need to quote predicates. I'm worried about
:tiptree:replace, are you using namespaces?
[:div '(attr? :foo :bar)] is equivalent to div *[foo][bar]
[[:div '(attr? :foo :bar)]] is equivalent to div[foo][bar]

Christophe Grand

unread,
Apr 15, 2009, 2:53:56 AM4/15/09
to clo...@googlegroups.com
David Nolen a écrit :

> One early thought, would you like me to extend the number of examples?
> I'm really getting into the nitty gritty of what's possible with
> Enlive and it would be nice to have a relatively informative list of
> possibilities distributed with the library vs. the single example
> that's in there right now ;)

With pleasure!

Christophe Grand

unread,
Apr 16, 2009, 7:15:31 AM4/16/09
to clo...@googlegroups.com
Tom,

The redesign is nearly over (at least from a user standpoint), you may
want to check it http://github.com/cgrand/enlive/tree/right

Christophe

Tom Hickey a écrit :

David Nolen

unread,
Apr 16, 2009, 4:24:05 PM4/16/09
to clo...@googlegroups.com
Because predicates in selectors no longer need to be quoted it seems you can't use Enlive selectors in a first class way with snippets:

(let [aselector [[:div (attr= :tiptree:widget "widgetA")]]]
  ((snippet "widget.html" aselector
   [some-map]
   [:div.value] (content "foo")) {}))

I believe this might be one of my final big requests :) I personally don't mind the quoted predicate forms, especially if this would simplify making selectors first class.  This would allow templates to dynamically generate snippets based on the properties of a particular node.

There's been a wild flurry of updates to Enlive recently and I am extremely excited about the possibilities.  Enlive is an idea which should be ripped off by every web framework worth talking about! ;) Thanks again for creating and maintaining it.

David Nolen

unread,
Apr 16, 2009, 6:54:09 PM4/16/09
to clo...@googlegroups.com
On second thought, this is actually not that critical for what I'm trying to accomplish, and I'm not sure yet if I'll ever use such a feature. Macros that define snippets will probably suffice.

(deftemplate my-app6 "app2.html"
  [widgets]
  [[:div (attr? :tiptree:replace)]] 
    (fn [node]
      (let [widgetType (:tiptree:replace (:attrs node))]
((snippet "widget.html" [[:div (attr= :tiptree:widget (str widgetType))]]
[widget]
[:div.value] (content (if widget
(:value widget)
"foo")))
((keyword widgetType) widgets)))))

(apply str 
       (my-app6 {:widgetA {:value "0"}, 
:widgetB {:value "1"}}))

Works for me, and this was in general the use case I was thinking of.

Christophe Grand

unread,
Apr 17, 2009, 4:22:25 AM4/17/09
to clo...@googlegroups.com
select, snippet, at and template are macro sugar. If you _really_ want
to use first-class selectors then you'll have to deal directly with
states machines and use at*, select* and snippet* (I'm going to improve
their usability).

While selectors aren't first class, they can be parametrized (as you did
in [[:div (attr= :tiptree:widget (str widgetType))]]). You can play with
compile-selector to see how selectors are expanded.

Regarding your code, I'd like to warn you against using snippet like
that for performance reason (and it won't get any better when I make
templates rendering faster).
It's better to extract snippets once for all:

(def snipgets
(let [divs (mapcat #(select % [[:div (attr? :tiptree:widget)]])
(html-resource "widget.html"))]
(into {}
(for [div divs]
[(-> div :attrs :tiptree:widget)
(snippet div [root]
[widget]
[:div.value] (content (if widget
(:value widget)
"foo")))))))

(deftemplate my-app6 "app2.html"
[widgets]
[[:div (attr? :tiptree:replace)]]
(fn [node]
(let [widgetType (:tiptree:replace (:attrs node))]
((snipgets widgetType) ((keyword widgetType) widgets)))))


David Nolen a écrit :
> <mailto:christo...@cgrand.net>> wrote:
> >
> >> Phil Hagelberg a écrit :
> >>
> >>
> >>> But I did notice you have the use test-is line commented
> out in the
> >>> implementation; it seems a bit unfortunate to have to
> uncomment that to
> >>> run the tests and hope you remember to re-comment it
> before you commit.
> >>>
> >> The last commit was during the transition to lazy-seq and
> test-is was
> >> broken.
> >> I'll fix that.
> >>
> >> --
> >> Professional:http://cgrand.net/(fr)
> <http://cgrand.net/%28fr%29>
> >> On Clojure:http://clj-me.blogspot.com/(en)
> <http://clj-me.blogspot.com/%28en%29>

Christophe Grand

unread,
Apr 17, 2009, 5:37:26 AM4/17/09
to clo...@googlegroups.com
Updating to reflect last changes:

(def snipgets
(let [divs (select (html-resource "widget.html")
[[:div (attr? :tiptree:widget)]])]


(into {}
(for [div divs]
[(-> div :attrs :tiptree:widget)
(snippet div [root]
[widget]
[:div.value] (content (if widget
(:value widget)
"foo")))))))

Christophe Grand a écrit :

David Nolen

unread,
Apr 17, 2009, 1:37:25 PM4/17/09
to clo...@googlegroups.com
Wow, thanks for the guidance, Enlive is improving at a rapid clip! ;)

>>>     <chris...@cgrand.net <mailto:christophe@

RZez...@gmail.com

unread,
May 6, 2009, 12:27:35 AM5/6/09
to Clojure
Either I've missed something, or Enlive *appears* to have problems
handling comment tags.

I was using Enlive against an already existing HTML file and kept
getting the following exception (please note it is HTML 4.01 Strict
and passed validation):

java.lang.RuntimeException: java.lang.IllegalArgumentException: Don't
know how to create ISeq from: Keyword

The following should reproduce:

(def res (html-resource (java.io.StringReader. "<html><body><h1></
h1><!-- oh noes, a comment --></body></html>")))

I don't have time to track down the problem any further, if it is a
problem and not something stupid on my part.

Thanks,
Ryan

Christophe Grand

unread,
May 6, 2009, 1:36:46 AM5/6/09
to clo...@googlegroups.com
Hello Ryan,

rzez...@gmail.com a écrit :


> Either I've missed something, or Enlive *appears* to have problems
> handling comment tags.
>

Indeed. I pushed a fix, please tell me whether it works for you now.

Thanks for the report.

Christophe

David Nolen

unread,
May 6, 2009, 2:33:28 AM5/6/09
to clo...@googlegroups.com
Seems to be working great now.

RZez...@gmail.com

unread,
May 7, 2009, 10:31:15 AM5/7/09
to Clojure


On May 6, 1:36 am, Christophe Grand <christo...@cgrand.net> wrote:
> Hello Ryan,
>
> rzeze...@gmail.com a écrit :> Either I've missed something, orEnlive*appears* to have problems
> > handling comment tags.
>
> Indeed. I pushed a fix, please tell me whether it works for you now.
>
> Thanks for the report.
>
> Christophe
>
> --
Works fine now. Thanks for the quick response, and for Enlive!

cody

unread,
Jun 27, 2009, 2:47:23 AM6/27/09
to Clojure


On May 6, 12:36 am, Christophe Grand <christo...@cgrand.net> wrote:
> Hello Ryan,
>
> rzeze...@gmail.com a écrit :> Either I've missed something, orEnlive*appears* to have problems
> > handling comment tags.
>
> Indeed. I pushed a fix, please tell me whether it works for you now.
>
> Thanks for the report.
>
> Christophe

Maybe unrelated, but

=>(html-resource (java.io.StringReader. "<!-- o noes a comment --
><html><head><title>t</title></head><body><h1>h</h1></body></html>"))

({:type :comment, :data " o noes a comment "})

Not the result I would expect.

Christophe Grand

unread,
Jun 27, 2009, 4:16:56 AM6/27/09
to clo...@googlegroups.com
Hi Cody!

On Sat, Jun 27, 2009 at 8:47 AM, cody <co...@koeninger.org> wrote:

Maybe unrelated, but

=>(html-resource (java.io.StringReader. "<!-- o noes a comment --
><html><head><title>t</title></head><body><h1>h</h1></body></html>"))

({:type :comment, :data " o noes a comment "})

Not the result I would expect.

Indeed. Fixed.

user=> (html-resource (java.io.StringReader. "<!-- o noes a comment --><html><head><title>t</title></head><body><h1>h</h1></body></html>"))
({:type :comment, :data " o noes a comment "} {:tag :html, :attrs nil, :content [{:tag :head, :attrs nil, :content [{:tag :title, :attrs nil, :content ["t"]}]} {:tag :body, :attrs nil, :content [{:tag :h1, :attrs nil, :content ["h"]}]}]})

Thanks for the report
 

cody

unread,
Jul 1, 2009, 4:45:17 PM7/1/09
to Clojure

On Jun 27, 3:16 am, Christophe Grand <christo...@cgrand.net> wrote:
> Indeed. Fixed.
>
> user=> (html-resource (java.io.StringReader. "<!-- o noes a comment
> --><html><head><title>t</title></head><body><h1>h</h1></body></html>"))
> ({:type :comment, :data " o noes a comment "} {:tag :html, :attrs nil,
> :content [{:tag :head, :attrs nil, :content [{:tag :title, :attrs nil,
> :content ["t"]}]} {:tag :body, :attrs nil, :content [{:tag :h1, :attrs nil,
> :content ["h"]}]}]})
>
> Thanks for the report
>
> Christophe


Thanks for the quick fix, seems to work on my pages that brought up
the issue.

Do you have any plans to support HTML fragments? Just as a quick
hack, I modified enlive to use the cyberneko parser with the document-
fragment feature on, and it will parse fragments, although selectors
stop working. I haven't had time to look more closely at the code,
but I'd assume this is because html fragments may not necessarily have
a single root.

The use case for this is inserting sub-templates, e.g. site-wide
common sidebars, footer, etc. Or do you see an alternate way to
accomplish that goal?

cody

unread,
Jul 1, 2009, 5:42:13 PM7/1/09
to Clojure


On Jul 1, 3:45 pm, cody <c...@koeninger.org> wrote:

> The use case for this is inserting sub-templates, e.g. site-wide
> common sidebars, footer, etc.  Or do you see an alternate way to
> accomplish that goal?

Eh, looks like I need to read earlier in the thread, apologies for the
noise, and thanks again for the fix.

Christophe Grand

unread,
Jul 1, 2009, 6:40:10 PM7/1/09
to clo...@googlegroups.com


I'm the one to blame for the lack of documentation.
I think snippet and defsnippet are whate you are looking for.
 
Reply all
Reply to author
Forward
0 new messages