weavejester / hiccup

Fast library for rendering HTML in Clojure
http://weavejester.github.io/hiccup
Eclipse Public License 1.0
2.69k stars 177 forks source link

Hiccup and Enlive #7

Open alienscience opened 14 years ago

alienscience commented 14 years ago

Hello, This is a feature request and not a bug. I was recently using Hiccup with Enlive and found that I had to parse Hiccup output into Clojure-XML format. This resulted in the following conversions:

hiccup datastructure -> string -> clojure-xml datastructure -> html page

This is a bit clunky and could potentially lead to performance problems.

The author of Enlive suggested that a function to convert Hiccup datastructures into clojure-xml form would be optimal for use with Enlive.

Developers on the #clojure-web freenode channel thought that such a facility would be useful elsewhere to produce clojure-xml compatible datastructures, since the Hiccup representation is much more convenient to write.

Would it be possible to add such a function to Hiccup? If not, would a patch to do this be accepted in principle?

Thanks in advance for your help. Saul

weavejester commented 14 years ago

It's possible in theory. It might need a bit of rearranging to do, but I'd be okay with it in principle. I've been meaning to tidy up Hiccup's source code for a while, as all that precompilation has made the code a bit labyrinthine.

fxt commented 13 years ago

Connecting hiccup and enlive would really be very useful. I have written a render-nodes function that takes a hiccup form and turns it into a node or seq of nodes that enlive is happy with. I had to write it inside src/hiccup/core.clj because it uses the normalize-element private function defined there. I did not spend time yet developing something to pre-compile the nodes like hiccup does for HTML. It would be great to have that too.

Here is the code I have written. Please, feel free to use it to add to hiccup. If you do not have time for it, please, let me know and I will continue work on my fork. Thank you for such a useful library. fxt

(defn- nodalize-attribute [[name value]]
  (cond
   (true? value) [(as-str name) (escape-html name)]
   (not value) nil
   :else [(as-str name) (escape-html value)]))

(defn- nodalize-attr-map [attrs]
  (if (nil? attrs)
    nil
    (->> attrs seq (map nodalize-attribute) (remove nil?)
         (apply concat) (apply sorted-map))))

(defmulti render-nodes
  "Turn a Clojure data type into a seq of XML nodes."
  {:private false}
  type)

(defn- nodalize-element
  "Render an tag vector as an XML node."
  [element]
  (let [[tag attrs content] (normalize-element element)]
    {:tag tag
     :attrs (nodalize-attr-map attrs)
     :content (render-nodes content)}))

(defmethod render-nodes IPersistentVector [element]
  (nodalize-element element))

(defmethod render-nodes ISeq [coll]
  (map render-nodes coll))

(defmethod render-nodes nil [_]
  nil)

(defmethod render-nodes :default [x]
  (str x))

BTW, I did some little bit of testing of the type (html [hiccup stuff]) == (enlive-html/emit* (render-nodes [hiccup stuff])) and got the two to agree. That is why I did a bit of transformation on the attribute map and used a sorted-map for it.

weavejester commented 13 years ago

I think if I was going to add this capability, I'd want the library refactored so that the output was controlled by a protocol that could be changed depending on whether you wanted a string of HTML, a string of XML or a tree of XML node maps.

So I don't think there should be a separate render-nodes function, but what you're written is a good start and feel free to continue refining it.

theJohnnyBrown commented 11 years ago

since #36, normalize-element is a public function, so you can use @fxt's code in your project like so:

(ns myproject.utils.hiccup2xml
  (:require [hiccup.compiler :as cpl])
  (:use [hiccup.util :only [as-str escape-html]])
  (:import (clojure.lang IPersistentVector ISeq)))

; ... as above
asmala commented 10 years ago

Enlive added a hiccup-like helper about a year ago (v1.1.0), so I wonder if this feature request is necessary anymore? @weavejester, mind taking a look and closing this ticket if you agree?

weavejester commented 10 years ago

I think there's benefit in allowing hiccup to emit different output structures. Having an output to a Clojure XML structure doesn't sound a bad idea. Aside from Enlive, it would allow the use of the clojure.xml libraries.

DerGuteMoritz commented 9 years ago

Hey James, I was wondering what the status of this issue and the refactor branch mentioned in #64 is?

weavejester commented 9 years ago

The latest branch is 2.0. I haven't done any more work on it in a while.