1 ;;; -*- Mode: Lisp; readtable: runes; -*-
2 ;;; (c) copyright 2007 David Lichteblau
4 ;;; This library is free software; you can redistribute it and/or
5 ;;; modify it under the terms of the GNU Library General Public
6 ;;; License as published by the Free Software Foundation; either
7 ;;; version 2 of the License, or (at your option) any later version.
9 ;;; This library is distributed in the hope that it will be useful,
10 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 ;;; Library General Public License for more details.
14 ;;; You should have received a copy of the GNU Library General Public
15 ;;; License along with this library; if not, write to the
16 ;;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 ;;; Boston, MA 02111-1307 USA.
21 (defclass klacks
:source
()
23 ;; fixme, terrible DTD kludges
24 (internal-declarations)
25 (external-declarations :initform nil
)
26 (dom-impl-dtd :initform nil
)
27 (dom-impl-entity-resolver :initform nil
)))
29 (defgeneric klacks
:close-source
(source))
31 (defgeneric klacks
:peek
(source))
32 (defgeneric klacks
:peek-value
(source))
33 (defgeneric klacks
:consume
(source))
35 (defgeneric klacks
:map-attributes
(fn source
))
36 (defgeneric klacks
:list-attributes
(source))
37 (defgeneric klacks
:get-attribute
(source lname
&optional uri
))
38 ;;;(defgeneric klacks:current-uri (source))
39 ;;;(defgeneric klacks:current-lname (source))
40 ;;;(defgeneric klacks:current-qname (source))
41 ;;;(defgeneric klacks:current-characters (source))
42 (defgeneric klacks
:current-cdata-section-p
(source))
43 (defgeneric klacks
:map-current-namespace-declarations
(fn source
))
45 (defgeneric klacks
:current-line-number
(source))
46 (defgeneric klacks
:current-column-number
(source))
47 (defgeneric klacks
:current-system-id
(source))
48 (defgeneric klacks
:current-xml-base
(source))
50 (defgeneric klacks
:find-namespace-binding
(prefix source
))
51 (defgeneric klacks
:decode-qname
(qname source
))
53 (defmacro klacks
:with-open-source
((var source
) &body body
)
54 `(let ((,var
,source
))
57 (klacks:close-source
,var
))))
59 (defun klacks:current-uri
(source)
60 (multiple-value-bind (key uri lname qname
) (klacks:peek source
)
61 (declare (ignore lname qname
))
62 (check-type key
(member :start-element
:end-element
))
65 (defun klacks:current-lname
(source)
66 (multiple-value-bind (key uri lname qname
) (klacks:peek source
)
67 (declare (ignore uri qname
))
68 (check-type key
(member :start-element
:end-element
))
71 (defun klacks:current-qname
(source)
72 (multiple-value-bind (key uri lname qname
) (klacks:peek source
)
73 (declare (ignore uri lname
))
74 (check-type key
(member :start-element
:end-element
))
77 (defun klacks:current-characters
(source)
78 (multiple-value-bind (key characters
) (klacks:peek source
)
79 (check-type key
(member :characters
))
82 (defun klacks:serialize-event
(source handler
&key
(consume t
))
83 (multiple-value-bind (key a b c
) (klacks:peek source
)
87 (sax:start-document handler
)
88 (loop for
(prefix . uri
) in
*initial-namespace-bindings
* do
89 (sax:start-prefix-mapping handler prefix uri
)))
92 ((klacks:current-cdata-section-p source
)
93 (sax:start-cdata source
)
94 (sax:characters handler a
)
95 (sax:end-cdata source
))
97 (sax:characters handler a
))))
98 (:processing-instruction
99 (sax:processing-instruction handler a b
))
101 (sax:comment handler a
))
103 (sax:start-dtd handler a b c
)
104 (when (slot-boundp source
'internal-declarations
)
105 (sax:start-internal-subset handler
)
106 (serialize-declaration-kludge
107 (slot-value source
'internal-declarations
)
109 (sax:end-internal-subset handler
))
110 (serialize-declaration-kludge
111 (slot-value source
'external-declarations
)
113 (sax:end-dtd handler
)
114 (sax:entity-resolver handler
115 (slot-value source
'dom-impl-entity-resolver
))
116 (sax::dtd handler
(slot-value source
'dom-impl-dtd
)))
118 (klacks:map-current-namespace-declarations
120 (sax:start-prefix-mapping handler prefix uri
))
122 (sax:start-element handler a b c
(klacks:list-attributes source
)))
124 (sax:end-element handler a b c
)
125 (klacks:map-current-namespace-declarations
127 (declare (ignore uri
))
128 (sax:end-prefix-mapping handler prefix
))
131 (loop for
(prefix . nil
) in
*initial-namespace-bindings
* do
132 (sax:end-prefix-mapping handler prefix
))
133 (setf result
(sax:end-document handler
)))
135 (error "serialize-event read past end of document"))
137 (error "unexpected klacks key: ~A" key
)))
139 (klacks:consume source
))
142 (defun serialize-declaration-kludge (list handler
)
144 for
(fn . args
) in list
145 do
(apply fn handler args
)))
147 (defun klacks:serialize-source
(source handler
)
149 (let ((document (klacks:serialize-event source handler
)))
151 (return document
)))))
153 (defclass klacksax
(sax:sax-parser
)
154 ((source :initarg
:source
)))
156 (defmethod sax:line-number
((parser klacksax
))
157 (klacks:current-line-number
(slot-value parser
'source
)))
159 (defmethod sax:column-number
((parser klacksax
))
160 (klacks:current-column-number
(slot-value parser
'source
)))
162 (defmethod sax:system-id
((parser klacksax
))
163 (klacks:current-system-id
(slot-value parser
'source
)))
165 (defmethod sax:xml-base
((parser klacksax
))
166 (klacks:current-xml-base
(slot-value parser
'source
)))
168 (defun klacks:serialize-element
(source handler
&key
(document-events t
))
169 (unless (eq (klacks:peek source
) :start-element
)
170 (error "not at start of element"))
171 (sax:register-sax-parser handler
(make-instance 'klacksax
:source source
))
172 (when document-events
173 (sax:start-document handler
))
175 (klacks:serialize-event source handler
)
177 (let ((key (klacks:peek source
)))
179 (:start-element
(recurse))
180 (:end-element
(return))
181 ((:characters
:comment
:processing-instruction
)
182 (klacks:serialize-event source handler
)))))
183 (klacks:serialize-event source handler
)))
185 (when document-events
186 (sax:end-document handler
)))
188 (defun klacks:find-element
(source &optional lname uri
)
190 (multiple-value-bind (key current-uri current-lname current-qname
)
196 (when (and (eq key
:start-element
)
198 (equal lname
(klacks:current-lname source
)))
200 (equal uri
(klacks:current-uri source
))))
202 (values key current-uri current-lname current-qname
)))))
203 (klacks:consume source
))))
205 (defun klacks:find-event
(source key
)
207 (multiple-value-bind (this a b c
)
213 (return (values this a b c
))))
214 (klacks:consume source
))))
216 (define-condition klacks-error
(xml-parse-error) ())
218 (defun klacks-error (fmt &rest args
)
219 (%error
'klacks-error
221 (format nil
"Klacks assertion failed: ~?" fmt args
)))
223 (defun klacks:expect
(source key
&optional u v w
)
224 (multiple-value-bind (this a b c
)
226 (unless (eq this key
) (klacks-error "expected ~A but got ~A" key this
))
227 (when (and u
(not (equal a u
)))
228 (klacks-error "expected ~A but got ~A" u a
))
229 (when (and v
(not (equal b v
)))
230 (klacks-error "expected ~A but got ~A" v b
))
231 (when (and w
(not (equal c w
)))
232 (klacks-error "expected ~A but got ~A" w c
))
233 (values this a b c
)))
235 (defun klacks:skip
(source key
&optional a b c
)
236 (klacks:expect source key a b c
)
237 (klacks:consume source
))
239 (defun invoke-expecting-element (fn source
&optional lname uri
)
240 (multiple-value-bind (key a b
)
242 (unless (eq key
:start-element
)
243 (klacks-error "expected ~A but got ~A" (or lname
"element") key
))
244 (when (and uri
(not (equal a uri
)))
245 (klacks-error "expected ~A but got ~A" uri a
))
246 (when (and lname
(not (equal b lname
)))
247 (klacks-error "expected ~A but got ~A" lname b
))
248 (multiple-value-prog1
250 (klacks:skip source
:end-element a b
))))
252 (defmacro klacks
:expecting-element
((source &optional lname uri
) &body body
)
253 `(invoke-expecting-element (lambda () ,@body
) ,source
,lname
,uri
))