Mercurial > lasercutter
view src/clojure/contrib/prxml.clj @ 10:ef7dbbd6452c
added clojure source goodness
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 21 Aug 2010 06:25:44 -0400 |
parents | |
children |
line wrap: on
line source
1 ;;; prxml.clj -- compact syntax for generating XML3 ;; by Stuart Sierra, http://stuartsierra.com/4 ;; March 29, 20096 ;; Copyright (c) 2009 Stuart Sierra. All rights reserved. The use and7 ;; distribution terms for this software are covered by the Eclipse8 ;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)9 ;; which can be found in the file epl-v10.html at the root of this10 ;; distribution. By using this software in any fashion, you are11 ;; agreeing to be bound by the terms of this license. You must not12 ;; remove this notice, or any other, from this software.15 ;; Change Log16 ;;17 ;; March 29, 2009: added *prxml-indent*18 ;;19 ;; January 4, 2009: initial version22 ;; See function "prxml" at the bottom of this file for documentation.25 (ns26 ^{:author "Stuart Sierra",27 :doc "Compact syntax for generating XML. See the documentation of \"prxml\"28 for details."}29 clojure.contrib.prxml30 (:use [clojure.contrib.string :only (escape as-str)]))32 (def33 ^{:doc "If true, empty tags will have a space before the closing />"}34 *html-compatible* false)36 (def37 ^{:doc "The number of spaces to indent sub-tags. nil for no indent38 and no extra line-breaks."}39 *prxml-indent* nil)41 (def ^{:private true} *prxml-tag-depth* 0)43 (def ^{:private true} print-xml) ; forward declaration45 (defn- escape-xml [s]46 (escape {\< "<"47 \> ">"48 \& "&"49 \' "'"50 \" """} s))52 (defn- prxml-attribute [name value]53 (print " ")54 (print (as-str name))55 (print "=\"")56 (print (escape-xml (str value)))57 (print "\""))59 (defmulti ^{:private true} print-xml-tag (fn [tag attrs content] tag))61 (defmethod print-xml-tag :raw! [tag attrs contents]62 (doseq [c contents] (print c)))64 (defmethod print-xml-tag :comment! [tag attrs contents]65 (print "<!-- ")66 (doseq [c contents] (print c))67 (print " -->"))69 (defmethod print-xml-tag :decl! [tag attrs contents]70 (let [attrs (merge {:version "1.0" :encoding "UTF-8"}71 attrs)]72 ;; Must enforce ordering of pseudo-attributes:73 (print "<?xml version=\"")74 (print (:version attrs))75 (print "\" encoding=\"")76 (print (:encoding attrs))77 (print "\"")78 (when (:standalone attrs)79 (print " standalone=\"")80 (print (:standalone attrs))81 (print "\""))82 (print "?>")))84 (defmethod print-xml-tag :cdata! [tag attrs contents]85 (print "<![CDATA[")86 (doseq [c contents] (print c))87 (print "]]>"))89 (defmethod print-xml-tag :doctype! [tag attrs contents]90 (print "<!DOCTYPE ")91 (doseq [c contents] (print c))92 (print ">"))94 (defmethod print-xml-tag :default [tag attrs contents]95 (let [tag-name (as-str tag)]96 (when *prxml-indent*97 (newline)98 (dotimes [n (* *prxml-tag-depth* *prxml-indent*)] (print " ")))99 (print "<")100 (print tag-name)101 (doseq [[name value] attrs]102 (prxml-attribute name value))103 (if (seq contents)104 (do ;; not an empty tag105 (print ">")106 (if (every? string? contents)107 ;; tag only contains strings:108 (do (doseq [c contents] (print-xml c))109 (print "</") (print tag-name) (print ">"))110 ;; tag contains sub-tags:111 (do (binding [*prxml-tag-depth* (inc *prxml-tag-depth*)]112 (doseq [c contents] (print-xml c)))113 (when *prxml-indent*114 (newline)115 (dotimes [n (* *prxml-tag-depth* *prxml-indent*)] (print " ")))116 (print "</") (print tag-name) (print ">"))))117 ;; empty tag:118 (print (if *html-compatible* " />" "/>")))))121 (defmulti ^{:private true} print-xml class)123 (defmethod print-xml clojure.lang.IPersistentVector [x]124 (let [[tag & contents] x125 [attrs content] (if (map? (first contents))126 [(first contents) (rest contents)]127 [{} contents])]128 (print-xml-tag tag attrs content)))130 (defmethod print-xml clojure.lang.ISeq [x]131 ;; Recurse into sequences, so we can use (map ...) inside prxml.132 (doseq [c x] (print-xml c)))134 (defmethod print-xml clojure.lang.Keyword [x]135 (print-xml-tag x {} nil))137 (defmethod print-xml String [x]138 (print (escape-xml x)))140 (defmethod print-xml nil [x])142 (defmethod print-xml :default [x]143 (print x))146 (defn prxml147 "Print XML to *out*. Vectors become XML tags: the first item is the148 tag name; optional second item is a map of attributes.150 Sequences are processed recursively, so you can use map and other151 sequence functions inside prxml.153 (prxml [:p {:class \"greet\"} [:i \"Ladies & gentlemen\"]])154 ; => <p class=\"greet\"><i>Ladies & gentlemen</i></p>156 PSEUDO-TAGS: some keywords have special meaning:158 :raw! do not XML-escape contents159 :comment! create an XML comment160 :decl! create an XML declaration, with attributes161 :cdata! create a CDATA section162 :doctype! create a DOCTYPE!164 (prxml [:p [:raw! \"<i>here & gone</i>\"]])165 ; => <p><i>here & gone</i></p>167 (prxml [:decl! {:version \"1.1\"}])168 ; => <?xml version=\"1.1\" encoding=\"UTF-8\"?>"169 [& args]170 (doseq [arg args] (print-xml arg)))