HAX documentation
[closure-common.git] / hax.lisp
blob7a6d6f0068bc3166d8298167a6e682096816d569
1 ;;; -*- show-trailing-whitespace: t; indent-tabs: nil -*-
2 ;;; ---------------------------------------------------------------------------
3 ;;; Title: An event API for the HTML parser, inspired by SAX
4 ;;; Created: 2007-10-14
5 ;;; Author: David Lichteblau
6 ;;; License: BSD
7 ;;; ---------------------------------------------------------------------------
8 ;;; (c) copyright 2005,2007 David Lichteblau
10 ;;; Redistribution and use in source and binary forms, with or without
11 ;;; modification, are permitted provided that the following conditions are
12 ;;; met:
13 ;;;
14 ;;; 1. Redistributions of source code must retain the above copyright
15 ;;; notice, this list of conditions and the following disclaimer.
16 ;;;
17 ;;; 2. Redistributions in binary form must reproduce the above copyright
18 ;;; notice, this list of conditions and the following disclaimer in the
19 ;;; documentation and/or other materials provided with the distribution
20 ;;;
21 ;;; THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
22 ;;; WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23 ;;; MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 ;;; IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25 ;;; INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 ;;; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 ;;; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 ;;; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 ;;; STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30 ;;; IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 ;;; POSSIBILITY OF SUCH DAMAGE.
33 (defpackage :hax
34 (:use :common-lisp)
35 (:export #:abstract-handler
36 #:default-handler
38 #:make-attribute
39 #:standard-attribute
40 #:find-attribute
41 #:attribute-name
42 #:attribute-value
43 #:attribute-specified-p
45 #:start-document
46 #:start-element
47 #:characters
48 #:end-element
49 #:end-document
50 #:comment))
52 (in-package :hax)
55 ;;;; ATTRIBUTE
57 (defgeneric attribute-name (attribute))
58 (defgeneric attribute-value (attribute))
59 (defgeneric attribute-specified-p (attribute))
61 (defclass standard-attribute ()
62 ((name :initarg :name :accessor attribute-name)
63 (value :initarg :value :accessor attribute-value)
64 (specified-p :initarg :specified-p :accessor attribute-specified-p)))
66 (defun make-attribute (name value &optional (specified-p t))
67 (make-instance 'standard-attribute
68 :name name
69 :value value
70 :specified-p specified-p))
72 (defun %rod= (x y)
73 ;; allow rods *and* strings *and* null
74 (cond
75 ((zerop (length x)) (zerop (length y)))
76 ((zerop (length y)) nil)
77 ((stringp x) (string= x y))
78 (t (runes:rod= x y))))
80 (defun find-attribute (name attrs)
81 (find name attrs :key #'attribute-name :test #'%rod=))
84 ;;;; ABSTRACT-HANDLER and DEFAULT-HANDLER
86 (defclass abstract-handler () ())
87 (defclass default-handler (abstract-handler) ())
89 (defgeneric start-document (handler name public-id system-id)
90 (:method ((handler null) name public-id system-id)
91 (declare (ignore name public-id system-id))
92 nil)
93 (:method ((handler default-handler) name public-id system-id)
94 (declare (ignore name public-id system-id))
95 nil))
97 (defgeneric start-element (handler name attributes)
98 (:method ((handler null) name attributes)
99 (declare (ignore name attributes))
100 nil)
101 (:method ((handler default-handler) name attributes)
102 (declare (ignore name attributes))
103 nil))
105 (defgeneric characters (handler data)
106 (:method ((handler null) data)
107 (declare (ignore data))
108 nil)
109 (:method ((handler default-handler) data)
110 (declare (ignore data))
111 nil))
113 (defgeneric end-element (handler name)
114 (:method ((handler null) name)
115 (declare (ignore name))
116 nil)
117 (:method ((handler default-handler) name)
118 (declare (ignore name))
119 nil))
121 (defgeneric end-document (handler)
122 (:method ((handler null)) nil)
123 (:method ((handler default-handler)) nil))
125 (defgeneric comment (handler data)
126 (:method ((handler null) data)
127 (declare (ignore data))
128 nil)
129 (:method ((handler default-handler) data)
130 (declare (ignore data))
131 nil))
134 ;;;; documentation
136 (setf (documentation (find-package :hax) t)
137 "An event protocol for HTML serialization, this package is similar
138 to the HAX protocol defined by cxml for XML serialization.
140 (Technically, this package should have been spelled SAH, but HAX
141 sounds better.)
143 Note that Closure HTML is not a streaming parser yet. Documents
144 are always parsed in full before the first HAX event is emitted.
145 In spite of this restriction, the HAX API is useful for HTML
146 serialization and transformation purposes, and for integration
147 with SAX.
149 @begin[HAX handlers]{section}
150 @aboutclass{abstract-handler}
151 @aboutclass{default-handler}
152 @end{section}
153 @begin[The attribute protocol]{section}
154 @aboutclass{standard-attribute}
155 @aboutfun{make-attribute}
156 @aboutfun{attribute-name}
157 @aboutfun{attribute-value}
158 @aboutfun{attribute-specified-p}
159 @end{section}
160 @begin[HAX events]{section}
161 @aboutfun{start-document}
162 @aboutfun{start-element}
163 @aboutfun{end-element}
164 @aboutfun{characters}
165 @aboutfun{comment}
166 @aboutfun{end-document}
167 @end{section}")
169 (setf (documentation 'abstract-handler 'type)
170 "@short{The superclass of all HAX handlers.}
172 Direct subclasses have to implement all event methods, since
173 no default methods are defined on this class.
175 Note that it is permissible to use handlers that are not
176 instances of this class in some circumstances.
178 In particular,
179 @code{nil} is a valid HAX handler and ignores all events.
181 In addition,
182 @a[http://common-lisp.net/project/cxml/sax.html#sax]{SAX handlers}
183 are valid HAX handlers (and vice versa), even though
184 hax:abstract-handler and sax:abstract-handler do not
185 share a specific superclass. HAX events sent to SAX handlers are
186 automatically re-signalled as XHTML SAX events, and SAX events sent
187 to HAX handlers are re-signalled as namespace-less HAX events.
189 However, user code should define subclasses of the documented
190 superclasses to enable the HAX/SAX bridging described above.
192 @see{chtml:parse}
193 @see{chtml:serialize-lhtml}
194 @see{chtml:serialize-pt}
195 @see{start-document}
196 @see{end-document}
197 @see{start-element}
198 @see{end-element}
199 @see{characters}
200 @see{comment}")
202 (setf (documentation 'default-handler 'type)
203 "@short{A no-op HAX handler.}
205 This class defines methods for all HAX events that do nothing.
206 It is useful as a superclass when implementing a HAX handler that
207 is interested in only some events and not others.
209 @see{chtml:parse}
210 @see{chtml:serialize-lhtml}
211 @see{chtml:serialize-pt}
212 @see{start-document}
213 @see{end-document}
214 @see{start-element}
215 @see{end-element}
216 @see{characters}
217 @see{comment}")
219 (setf (documentation 'standard-attribute 'type)
220 "@short{An implementation of the HAX attribute protocol.}
222 A standard class implementing the generic functions for HAX
223 attributes. Instances of this class can be passed to
224 @fun{hax:start-element} in the list of attributes.
226 @see-slot{attribute-name}
227 @see-slot{attribute-value}
228 @see-slot{attribute-specified-p}
229 @see-constructor{make-instance}")
231 (setf (documentation 'make-attribute 'function)
232 "@arg[name]{a string/rod}
233 @arg[value]{a string/rod}
234 @arg[specified-p]{a boolean, default is @code{t}}
235 @return{an instance of @class{standard-attribute}.}
236 @short{Creates a HAX attribute.}
238 Creates an instance that can be used with the generic functions
239 for HAX attributes. The result can be passed to
240 @fun{hax:start-element} in the list of attributes.
242 @see{attribute-name}
243 @see{attribute-value}
244 @see{attribute-specified-p}")
246 (setf (documentation 'find-attribute 'function)
247 "@arg[name]{a string/rod}
248 @arg[attrs]{a list of attributes}
249 @return{an attribute, or nil}
250 @short{Searches for an attribute by name.}
252 Returns the first attribute in @var{attrs} with the specified name,
253 or @code{nil} if no such attribute was found.
255 @see{attribute-name}")
257 (setf (documentation 'attribute-name 'function)
258 "@arg[instance]{any class implementing this function}
259 @return{a string/rod}
260 @short{Return an attribute's name.}
262 Instances of this classes implementing this function can be passed to
263 @fun{hax:start-element} in the list of attributes.
265 @see{attribute-value}
266 @see{attribute-specified-p}")
268 (setf (documentation 'attribute-value 'function)
269 "@arg[instance]{any class implementing this function}
270 @return{a string/rod}
271 @short{Return an attribute's value.}
273 Instances of this classes implementing this function can be passed to
274 @fun{hax:start-element} in the list of attributes.
276 @see{attribute-name}
277 @see{attribute-specified-p}")
279 (setf (documentation 'attribute-specified-p 'function)
280 "@arg[instance]{any class implementing this function}
281 @return{a string/rod}
282 @short{Return whether the attribute was contained the parsed document.}
284 Attributes return @code{nil} here if they resulted from a default
285 value declaration in a DTD.
287 Instances of this classes implementing this function can be passed to
288 @fun{hax:start-element} in the list of attributes.
290 @see{attribute-name}
291 @see{attribute-value}")
293 (setf (documentation 'start-document 'function)
294 "@arg[handler]{a HAX/SAX handler
295 (see @class{abstract-handler} for details)}
296 @arg[name]{root element name, a rod/string}
297 @arg[public-id]{nil or the Public ID, a rod/string}
298 @arg[system-id]{nil or the System ID/URI, a rod/string}
299 @return{unspecified}
300 @short{Signals the beginning on an HTML document.}
302 This is the first event sent to any handler.
304 If @var{system-id} is non-nil, the document includes a doctype
305 declaration.
307 @see{start-element}
308 @see{end-element}
309 @see{characters}
310 @see{comment}
311 @see{end-document}")
313 (setf (documentation 'start-element 'function)
314 "@arg[handler]{a HAX/SAX handler
315 (see @class{abstract-handler} for details)}
316 @arg[name]{root element name, a rod/string}
317 @arg[attributes]{a list of attributes}
318 @return{unspecified}
319 @short{Signals the beginning of an HTML element.}
321 This event corresponds to the opening tag of an element.
323 Elements of the attribute list can have any class, but must implement
324 the generic functions for attributes. See @class{standard-attribute}
325 for the built-in attribute implementation.
327 @see{find-attribute}
328 @see{start-document}
329 @see{end-element}
330 @see{characters}
331 @see{comment}
332 @see{end-document}")
334 (setf (documentation 'end-element 'function)
335 "@arg[handler]{a HAX/SAX handler
336 (see @class{abstract-handler} for details)}
337 @arg[name]{root element name, a rod/string}
338 @return{unspecified}
339 @short{Signals the end of an HTML element.}
341 This event corresponds to the closing tag of an element.
343 @see{start-document}
344 @see{start-element}
345 @see{characters}
346 @see{comment}
347 @see{end-document}")
349 (setf (documentation 'characters 'function)
350 "@arg[handler]{a HAX/SAX handler
351 (see @class{abstract-handler} for details)}
352 @arg[data]{rod/string}
353 @return{unspecified}
354 @short{Signals character data.}
356 This event represents character data in a document.
358 @see{start-document}
359 @see{start-element}
360 @see{end-element}
361 @see{comment}
362 @see{end-document}")
364 (setf (documentation 'comment 'function)
365 "@arg[handler]{a HAX/SAX handler
366 (see @class{abstract-handler} for details)}
367 @arg[data]{rod/string}
368 @return{unspecified}
369 @short{Signals a comment.}
371 This event represents a comment.
373 @see{start-document}
374 @see{start-element}
375 @see{end-element}
376 @see{characters}
377 @see{end-document}")
379 (setf (documentation 'end-document 'function)
380 "@arg[handler]{a HAX/SAX handler
381 (see @class{abstract-handler} for details)}
382 @return{The return value of this function depends on the handler class.}
383 @short{Signals the end on an HTML document.}
385 This is the last event sent to any handler, and signals the end of
386 serialization.
388 The return value of this function is usually returned to user code
389 by higher-level serialization functions and can be considered the
390 result of serialization and \"return value\" of the handler.
392 @see{start-document}
393 @see{start-element}
394 @see{end-element}
395 @see{characters}
396 @see{comment}")