* trac-ticket.el: Removed.
[ShellArchive.git] / xmlgen.el
blob7b0c8af6aa1bbf62b4626cb8620dbadc599bb2c2
1 ;;; xml-gen.el --- A DSL for generating XML.
3 ;; Copyright (C) 2008 Philip Jackson
5 ;; Author: Philip Jackson <phil@shellarchive.co.uk>
6 ;; Version: 0.4
8 ;; This file is not currently part of GNU Emacs.
10 ;; This program is free software; you can redistribute it and/or
11 ;; modify it under the terms of the GNU General Public License as
12 ;; published by the Free Software Foundation; either version 2, or (at
13 ;; your option) any later version.
15 ;; This program is distributed in the hope that it will be useful, but
16 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 ;; General Public License for more details.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with this program ; see the file COPYING. If not, write to
22 ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA.
25 ;;; Commentary:
27 ;; Generate xml using sexps with the function `xmlgen':
29 ;; (xmlgen '(p :class "big")) => "<p class=\"big\" />")
30 ;; (xmlgen '(p :class "big" "hi")) => "<p class=\"big\">hi</p>")
32 ;; (xmlgen '(html
33 ;; (head
34 ;; (title "hello")
35 ;; (meta :something "hi"))
36 ;; (body
37 ;; (h1 "woohhooo")
38 ;; (p "text")
39 ;; (p "more text"))))
41 ;; produces this (though wrapped):
43 ;; <html>
44 ;; <head>
45 ;; <title>hello</title>
46 ;; <meta something="hi" />
47 ;; </head>
48 ;; <body>
49 ;; <h1>woohhooo</h1>
50 ;; <p>text</p>
51 ;; <p>more text</p>
52 ;; </body>
53 ;; </html>
55 (eval-when-compile (require 'cl))
57 (defvar xmlgen-escape-attribute-vals t
58 "When non-nil xmlgen will escape the characters <>'\"&' in an
59 attribute value.")
61 (defvar xmlgen-escape-elm-vals t
62 "When non-nil xmlgen will escape the characters <>'\"&' in an
63 elements content.")
65 (defvar xmlgen-escapees
66 '(("&" . "&amp;")
67 ("'" . "&apos;")
68 ("\"" . "&quot;")
69 ("<" . "&lt;")
70 (">" . "&gt;"))
71 "List of (find . replace) pairs for escaping. See
72 `xmlgen-escape-elm-vals' and `xmlgen-escape-attribute-vals'")
74 ;;;###autoload
75 (defun xmlgen (form &optional in-elm level)
76 "Convert a sexp to xml:
77 '(p :class \"big\")) => \"<p class=\\\"big\\\" />\""
78 (let ((level (or level 0)))
79 (cond
80 ((numberp form) (number-to-string form))
81 ((stringp form) form)
82 ((listp form)
83 (destructuring-bind (xml attrs) (xmlgen-extract-plist form)
84 (let ((el (car xml)))
85 (unless (symbolp el)
86 (error "Element must be a symbol (got '%S')." el))
87 (setq el (symbol-name el))
88 (concat "<" el (xmlgen-attr-to-string attrs)
89 (if (> (length xml) 1)
90 (concat ">" (mapconcat
91 '(lambda (s) (xmlgen s el (1+ level)))
92 (cdr xml)
93 "")
94 "</" el ">")
95 "/>"))))))))
97 (defun xmlgen-string-escape (string)
98 "Escape STRING for inclusion in some XML."
99 (when (stringp string)
100 (mapc
101 '(lambda (e)
102 (setq string
103 (replace-regexp-in-string (car e) (cdr e) string)))
104 xmlgen-escapees))
105 string)
107 (defun xmlgen-attr-to-string (plist)
108 "Convert a plist to xml style attributes."
109 (let ((res ""))
110 (while plist
111 (let ((sym (pop plist))
112 (val (pop plist)))
113 (setq res
114 (concat res " " (substring (symbol-name sym) 1 ) "=\""
115 (if xmlgen-escape-attribute-vals
116 (xmlgen-string-escape val)
117 val)
118 "\""))))
119 res))
121 (defun xmlgen-extract-plist (list)
122 "Extract a plist from LIST returning the original list without
123 the plist and the plist."
124 (let ((nlist '())
125 (plist '())
126 (last-keyword nil))
127 (mapc
128 '(lambda (item)
129 (let ((item (pop list)))
130 (cond
131 (last-keyword
132 (setq plist (append plist (list last-keyword)))
133 (setq plist (append plist (list item)))
134 (setq last-keyword nil))
135 ((keywordp item) (setq last-keyword item))
136 (t (setq nlist (append nlist (list item)))))))
137 list)
138 (when last-keyword
139 (error "No value to satisfy keyword '%s'"
140 (symbol-name last-keyword)))
141 (list nlist plist)))
143 (provide 'xmlgen)