Compojure HTML Formatting

3.4k Views Asked by At

I'm relatively new to Clojure and a complete HTML/Compojure virgin. I'm trying to use Compojure to create static pages of HTML using a function similar to this:

(defn fake-write-html
  [dir args]
  (let [file (str dir *file-separator* *index-file*)
        my-html (html
                  (doctype :html4)
                  [:html
                   [:head
                    [:title "Docs and Dirs:"]]
                   [:body
                    [:div
                     [:h2 "A nice title"]]
                    [:div
                     [:ul
                      [:li "One"]
                      [:li "Two"]]]]])]
    (clojure.contrib.duck-streams/spit file my-html)))

The function just writes HTML to a file. (The args argument is irrelevant here. Just there to assure the example compiles and runs in my program.)

"Programming Clojure" indicated that the call to the html function would produce formatted HTML -- multiple lines with indentation. All I get is the doc type as expected followed by all of the HTML on a single line. HTML Tidy doesn't find any issues with the content of the output file. It comes out as a single line if I println it at the REPL too.

Is there something else needed to get formatted output?

5

There are 5 best solutions below

1
On BEST ANSWER

The formatting of HTML output in Compojure was removed for performance and complexity reasons. To get formatted output you will probably have to write your own printer function.

I usually output HTML as Compojure sees fit and use Firebug to view it live in my browser. Firebug will display it nicely formatted no matter if it's really all on one line or not. This works well enough most of the time. If you need to serialize this HTML in a readable form, you could keep it as Clojure vectors and sexps and serialize it that way.

0
On

If anyone is still looking at this query, you need the hiccup library. If formats HTML from exactly the Clojure data structure shown.

So


(require '[hiccup.core :refer [html]])

(defn fake-write-html
  [dir args]
  (let [file (str dir *file-separator* *index-file*)
        my-html (html
                  [:html
                   [:head
                    [:title "Docs and Dirs:"]]
                   [:body
                    [:div
                     [:h2 "A nice title"]]
                    [:div
                     [:ul
                      [:li "One"]
                      [:li "Two"]]]]])]
    (clojure.contrib.duck-streams/spit file my-html)))

will work exactly as the original poster intended. Strongly recommended.

0
On

The above did not work for me. I changed this a bit.

add this [jtidy "4aug2000r7-dev"] to project.clj

(:use clojure.core)
(:import (org.w3c.tidy Tidy))
(:import (java.io ByteArrayInputStream ByteArrayOutputStream)))



(defn configure-pretty-printer
 "Configure the pretty-printer (an instance of a JTidy Tidy class) to
generate output the way we want -- formatted and without sending warnings.
 Return the configured pretty-printer."
[]
(doto (new Tidy)
(.setSmartIndent true)
;(.setTrimEmptyElements true)
(.setShowWarnings false)
(.setQuiet true)))

(defn pretty-print-html
  "Pretty-print the html and return it as a string."
 [html]
(let [swrtr ( ByteArrayOutputStream.)]
  (.parse (configure-pretty-printer) (ByteArrayInputStream. (.getBytes (str html)))  swrtr)
(str swrtr)))
1
On

There are tons of HTML pretty printers available for Java, notably JTidy, a Java port of HTML Tidy. You can easily feed Clojure's output through this library programatically and get neatly indented and formatted HTML back.

HTML Tidy is also available as a command-line program for Unix if you'd care to go that route -- you can just pipe your HTML through it like any other shell program.

0
On

Although Brian's answer pointed me to Firebug, enabling the debugging I wanted, I was just to obsessive-compulsive to leave it alone. Following up on kwertii's pointer to JTidy, I included the following code in my program.

Edit: Simplified the code somewhat

(ns net.dneclark.someprogram
  (:gen-class)
  ...
  (:import (org.w3c.tidy Tidy))
      )

  ...

(defn configure-pretty-printer
  "Configure the pretty-printer (an instance of a JTidy Tidy class) to
generate output the way we want -- formatted and without sending warnings.
Return the configured pretty-printer."
  []
  (doto (new Tidy)
    (.setSmartIndent true)
    (.setTrimEmptyElements true)
    (.setShowWarnings false)
    (.setQuiet true)))

(defn pretty-print-html
  "Pretty-print the html and return it as a string."
  [html]
  (let [swrtr (new StringWriter)]
    (.parse (configure-pretty-printer) (new StringReader (str html)) swrtr)
    (str swrtr)))

I added the jtidy-r938.jar to my project (NetBeans using the enclojure plugin) and imported it. The configuration function tells the parser to output formatted, indented HTML and skip the warnings. The return value from the pretty-printer function is now nicely formatted whether I open it with Firebug or a simple text editor.