(html
(:body
(:p :id "title" "aiueo")))
;=> "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"
; \"http://www.w3.org/TR/html4/loose.dtd\">
; <html><body><p id=\"title\">aiueo</p></body></html>"
Macros, provided by CL-MARKUP, generates really efficient code. They convert into just a calling `write-string' as possible. See following two examples and how CL-MARKUP expands them.
Example A:
;; Example A
(let ((*output-stream* t))
(loop for (link . title) in '(("http://zappa.com/" . "Frank Zappa")
("http://marcusmiller.com/" . "Marcus Miller")
("http://www.milesdavis.com/" . "Miles Davis"))
do (markup (:a :href link
(:b title))
(:br))))
;; Example A: generated by CL-MARKUP
(let ((*output-stream* t))
(loop for (link . title) in '(("http://zappa.com/" . "Frank Zappa")
("http://marcusmiller.com/" . "Marcus Miller")
("http://www.milesdavis.com/" . "Miles Davis"))
do (if *output-stream*
(progn (write-string "<a href=\"" *output-stream*)
(write-string (escape-string (cl-markup::ensure-string link))
*output-stream*)
(write-string "\"><b>" *output-stream*)
(write-string (escape-string (cl-markup::ensure-string title))
*output-stream*)
(write-string "</b></a><br />" *output-stream*))
(with-output-to-string (#:G0)
(write-string "<a href=\"" #:G0)
(write-string (escape-string (cl-markup::ensure-string link)) #:G0)
(write-string "\"><b>" #:G0)
(write-string (escape-string (cl-markup::ensure-string title)) #:G0)
(write-string "</b></a><br />" #:G0)))))
Example B:
;; Example B
(markup
(:table :border 0 :cellpadding 4
(loop for i below 25 by 5
collect
(markup
(:tr :align "right"
(loop for j from i below (+ i 5)
collect
(markup
(:td :bgcolor
(if (oddp j)
"pink"
"green")
(format nil "~@R" (1+ j))))))))))
;; Example B: generated by CL-MARKUP
(if *output-stream*
(progn (write-string "<table border=\"0\" cellpadding=\"4\">"
*output-stream*)
(write-string (let ((#:G0
(loop for i below 25 by 5
collect (markup
(:tr
:align
"right"
(loop for j
from
i
below
(+ i 5)
collect (markup
(:td
:bgcolor
(if
(oddp j)
"pink"
"green")
(format
nil
"~@r"
(1+ j))))))))))
(if (consp #:G0)
(with-output-to-string (#:G1)
(dolist (#:G2 #:G0)
(write-string #:G2 #:G1)))
#:G0))
*output-stream*)
(write-string "</table>" *output-stream*))
(with-output-to-string (#:G0)
(write-string "<table border=\"0\" cellpadding=\"4\">"
#:G0)
(write-string (let
((#:G0
(loop for i below 25 by 5
collect (markup
(:tr
:align
"right"
(loop for j
from
i
below
(+ i 5)
collect (markup
(:td
:bgcolor
(if
(oddp j)
"pink"
"green")
(format
nil
"~@r"
(1+
j))))))))))
(if
(consp #:G0)
(with-output-to-string
(#:G1)
(dolist
(#:G2 #:G0)
(write-string #:G2 #:G1)))
#:G0))
#:G0)
(write-string "</table>" #:G0)))
The generated code looks more complicate than CL-WHO's one, because CL-MARKUP decide where to output the result in run-time.
markup
is the most simple way to generate HTML.
(markup (:p "あいうえお"))
;=> "<p>あいうえお</p>"
CL-MARKUP outputs tags in XHTML style by default.
(markup (:br))
;=> "<br />"
You can change the markup language to set *markup-language*
to the other one.
(eval-when (:compile-toplevel :load-toplevel :execute)
(setf *markup-language* :html))
Don't forget to wrap setf
with eval-when
, because markup
needs it to optimize it's expanded code heavily in compile-time.
This also means, you CAN'T write the following code.
;; THIS IS A WRONG EXAMPLE!!
(let ((*markup-language* :html))
(markup (:br)))
;=> "<br />"
If you really want to delay the decision until run-time, use markup*
, a function version of markup
.
;; This is a correct one.
;; But I don't recommend this for performance.
(let ((*markup-language* :xhtml))
(markup* '(:br)))
;=> "<br>"
Other macros html
, xhtml
and xml
, outputs DOCTYPE before markup
.
(html (:p "あいうえお") (:br))
;=> "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\"><html><p>あいうえお</p><br></html>"
(xhtml (:p "あいうえお") (:br))
;=> "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"><html><p>あいうえお</p><br /></html>"
(xml (:p "あいうえお") (:br))
;=> "<?xml version=\"1.0\" encoding=\"UTF-8\"?><p>あいうえお</p><br />"
Embedded strings will be escaped automatically.
(markup (:p "Tiffany & Co."))
;=> "<p>Tiffany & Co.</p>"
If you don't hope this behavior, set *auto-escape*
nil or use raw
in order to suppress it temporally.
(let ((*auto-escape* nil))
(markup (:p "Tiffany & Co.")))
;=> "<p>Tiffany & Co.</p>"
(markup (:p (raw "Tiffany & Co.")))
;=> "<p>Tiffany & Co.</p>"
In a contrasting case, esc
is available about it.
Markup macros returns html as a string. You can customize this behavior using *output-stream*
.
;; Default behavior
(let (*output-stream*)
(markup (:p "hoge"))
;=> "<p>hoge</p>"
;; Output to *standard-output* directly
(let ((*output-stream* t))
(markup (:p "hoge")))
;;=> <p>hoge</p>
;=> "<p>hoge</p>"
You can embeded Lisp code in a tag body.
(markup (:ul (loop for item in '(1 2 3) collect (markup (:li item)))))
But, markup
is too long to embed. CL-MARKUP provides an usefull syntax to write more shortly. To enable it, put (enable-markup-syntax)
before.
(enable-markup-syntax)
#M(:ul (loop for item in '(1 2 3) collect #M(:li item))))
Copyright (c) 2011 Eitarow Fukamachi.
Licensed under the LLGPL License.