Strangeness with html-content

132 views
Skip to first unread message

David Della Costa

unread,
Apr 27, 2013, 8:09:21 AM4/27/13
to enliv...@googlegroups.com
Hi folks,

I'm trying to figure out if I'm doing something incorrectly or if this is an issue with Enlive (I suspect the former).

I have this defsnippet:

                                                                                                                                      
(html/defsnippet show-post-snippet                                                                                                                            
  "templates/posts/show.html"                                                                                                                                 
  [:div#content-wrapper]                                                                                                                                      
  [post]                                                                                                                                                      
  [:div.container] (html/html-content (:content post)))

The (:content post) bit is pulling raw HTML from a map.

However, sometimes it breaks my HTML.  For example, this always goes from this:

<pre>
 <p>Test</p>
</pre>

To something like

<pre>
</pre><p>Test</p>

when actually being shown.  That is, it seems to be extracting the p tag inside the pre tag and putting it outside the pre tag.

When I dump out the nodes, I see this:

({:tag :html, :attrs nil, :content                                                                                                                            
  ({:tag :body, :attrs nil, :content                                                                                                                          
    ({:tag :pre, :attrs nil, :content ()}                                                                                                                     
     {:tag :p, :attrs nil, :content (test)}                                                                                                                   
)})})

The p tag is clearly outside of the pre tag in the node structure.  What's going on with this?

Thanks!

Dave

xavi

unread,
Apr 27, 2013, 10:25:19 AM4/27/13
to enliv...@googlegroups.com
I think it's the same problem I was having
https://groups.google.com/forum/#!topic/enlive-clj/ZdF83EdTfrs

I think that despite what the README says about pluggable parsers being available in 1.1.1 ( https://github.com/cgrand/enlive#pluggable-parsers-111 ), they're not. I understand the code for that is ready, in GitHub, it will be part of 1.1.2, but it hasn't been released to Clojars yet. In the meantime, in order to use JSoup now I downloaded the latest Enlive code from GitHub and I added it to my project.

xavi

David Della Costa

unread,
May 11, 2013, 3:43:57 AM5/11/13
to enliv...@googlegroups.com
xavi, sorry I took so long to respond.  Thanks for your tip.

Unfortunately, that doesn't seem to have resolved it.  I tried installing enlive 1.1.2 locally, and setting my parser globally like so:

   [net.cgrand.enlive-html :as html]                                                                                                                          
   [net.cgrand.jsoup :as jsoup]))                                                                                                                             
                                                                                                                                                              
(html/set-ns-parser! jsoup/parser)

...

Still, I'm getting the same crap as before.  Am I doing something incorrectly?

Thanks!

Dave

2013年4月27日土曜日 23時25分19秒 UTC+9 xavi:

xavi

unread,
May 11, 2013, 8:56:25 AM5/11/13
to enliv...@googlegroups.com

It worked to solve my particular problem, but now I've been playing with this in your particular context and it doesn't.

According to the README, set-ns-parser! sets the parser for the declaring ns ( https://github.com/cgrand/enlive#pluggable-parsers-111 ), but if in the REPL I do...

(require '[net.cgrand.enlive-html :as h])
(require '[net.cgrand.jsoup :as jsoup])
(h/set-ns-parser! jsoup/parser)
; => {:net.cgrand.enlive-html/options {:parser #<jsoup$parser net.cgrand.jsoup$parser@24e1fb6c>}}
(h/html-snippet "<pre><p>Test</p></pre>")
; => ({:tag :body, :attrs nil, :content ({:tag :pre, :attrs nil, :content nil} {:tag :p, :attrs nil, :content ("Test")})})

That was not the expected result if jsoup is used. Looking at the source code for html-snippet, I see that that it calls to html-resource, and this gets the parser to use from *options*, so... I added a  (println "*options*: " *options*) to check that *options* contains the configured parser, however what's printed is...

*options*:  {:parser #<tagsoup$parser net.cgrand.tagsoup$parser@79b0edb2>}

Looking at Enlive source code again, I see that when the parser is configure with (h/set-ns-parser! jsoup/parser), the value of *options* is not changed. The only place where *options* is changed is in the with-options macro. I don't understand why set-ns-parser! doesn't change *options*, but anyway, let's try with with-options...

(h/with-options {:parser jsoup/parser}
    (h/html-snippet "<pre><p>Test</p></pre>"))

The result is...
java.lang.IllegalArgumentException: No matching method found: parse (NO_SOURCE_FILE:0)

Looking at the html-snippet definition, I see that it calls html-resource with a java.io.StringReader., and html-resource in turn calls the multimethod get-resource (with the reader and the parser from *options*). When passed a reader (java.io.Reader), get-resource simply calls the parser (named 'loader' here) with that reader. Looking at the source code for the configured parser, jsoup/parser, I see this is a function (I find strange that this function is named 'parser'... wouldn't be 'parse' a better name? anyway, I'm digressing) that calls Java's org.jsoup.Jsoup.parse() method. Looking at the Jsoup docs ( http://jsoup.org/apidocs/org/jsoup/Jsoup.html ) it seems there's no any parse() method that accepts a reader, and that seems to be the ultimate cause of the java.lang.IllegalArgumentException .

As far as I understand, this is a problem that has to be solved in the Enlive code. I would like to provide a pull-request with a solution, but I don't fully understand how parser configuration is supposed to work, or how to work around the fact that Jsoup's parse() doesn't accept readers (I tried modifying Enlive's html-snippet to call html-resouce with a ByteArrayInputStream, which is accepted by Jsoup's parse(), instead of a StringReader, but I didn't get the expected result). At least I hope my investigation can be useful for someone that maybe could provide a solution :)

Cheers!

David Della Costa

unread,
May 12, 2013, 10:00:30 AM5/12/13
to enliv...@googlegroups.com
Wow, xavi, thanks for this excellent debugging work!  Very much appreciated.

Yes, I think for now I've resigned myself to not solving this particular case--it's an edge case with our user base and doesn't really come up often, but I thought I would try to solve it if possible.  I'll see if I can continue where you left off, but I'm not sure how much further I'll get.  In any case, I appreciate you shedding light on the issue.

Thanks!

Dave

2013年5月11日土曜日 21時56分25秒 UTC+9 xavi:
Reply all
Reply to author
Forward
0 new messages