1 ;;; -*- show-trailing-whitespace: t; indent-tabs: nil -*-
3 ;;; Copyright (c) 2007 David Lichteblau. All rights reserved.
5 ;;; Redistribution and use in source and binary forms, with or without
6 ;;; modification, are permitted provided that the following conditions
9 ;;; * Redistributions of source code must retain the above copyright
10 ;;; notice, this list of conditions and the following disclaimer.
12 ;;; * Redistributions in binary form must reproduce the above
13 ;;; copyright notice, this list of conditions and the following
14 ;;; disclaimer in the documentation and/or other materials
15 ;;; provided with the distribution.
17 ;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED
18 ;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 ;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 ;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
21 ;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 ;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23 ;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 ;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 ;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 ;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 ;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 (in-package :cxml-stp-impl
)
32 (declaim (optimize (debug 2)))
34 (defun make-builder ()
35 "@return{STP builder, a SAX handler}
36 @short{This function creates SAX handler that constructs an STP document.}
38 The builder processes SAX events and can be used with any
39 function generating such events, in particular with cxml:parse-file.
41 Examples. Parsing a file:
42 @begin{pre}(cxml:parse #p\"example.xml\" (stp:make-builder))@end{pre}
44 @begin{pre}(cxml:parse \"<example/>\" (stp:make-builder))@end{pre}
47 (make-instance 'builder
))
49 (defclass builder
(sax:content-handler
)
50 ((nodes :initform nil
:accessor builder-nodes
)
51 (doctype :initform nil
:accessor builder-doctype
)
52 (namespace-declarations :initform nil
:accessor namespace-declarations
)
53 (internal-subset-sink :initform nil
54 :accessor builder-internal-subset-sink
)))
56 (defmethod sax:start-document
((builder builder
))
57 (push (make-instance 'document
) (builder-nodes builder
)))
59 (defun builder-append (builder x
)
60 (let ((parent (car (builder-nodes builder
))))
61 (%unchecked-insert-child parent x
(length (%children parent
)))))
63 (defmethod sax:start-dtd
((builder builder
) name publicid systemid
)
64 (setf (builder-doctype builder
)
65 (make-document-type name systemid publicid
""))
66 (builder-append builder
(builder-doctype builder
)))
68 (defmethod sax:start-internal-subset
((builder builder
))
69 (setf (builder-internal-subset-sink builder
) (cxml:make-string-sink
)))
71 (macrolet ((def (name &rest args
)
72 `(defmethod ,name
((builder builder
) ,@args
)
73 (let ((sink (builder-internal-subset-sink builder
)))
74 (when sink
(,name sink
,@args
))))))
75 (def sax
:unparsed-entity-declaration name public-id system-id notation-name
)
76 (def sax
:external-entity-declaration kind name public-id system-id
)
77 (def sax
:internal-entity-declaration kind name value
)
78 (def sax
:notation-declaration name public-id system-id
)
79 (def sax
:element-declaration name model
)
80 (def sax
:attribute-declaration element-name attribute-name type default
))
82 (defmethod sax:end-internal-subset
((builder builder
))
83 (setf (internal-subset (builder-doctype builder
))
86 (builder-internal-subset-sink builder
))))
87 (setf (builder-internal-subset-sink builder
) nil
))
89 (defmethod sax::dtd
((builder builder
) dtd
)
90 (when (builder-doctype builder
)
91 (setf (dtd (builder-doctype builder
)) dtd
)))
93 (defmethod sax:start-prefix-mapping
((builder builder
) prefix uri
)
94 (push (cons (or prefix
"") uri
) (namespace-declarations builder
)))
96 (defmethod sax:start-element
((builder builder
) uri lname qname attrs
)
97 (let ((element (make-element qname uri
)))
98 (setf (%base-uri element
) (sax:xml-base builder
))
100 (let ((uri (sax:attribute-namespace-uri a
)))
101 (unless (equal uri
"http://www.w3.org/2000/xmlns/")
102 (let ((b (make-attribute (sax:attribute-value a
)
103 (sax:attribute-qname a
)
105 (add-attribute element b
)))))
106 (builder-append builder element
)
107 (loop for
(prefix . uri
) in
(namespace-declarations builder
) do
108 (unless (find-namespace prefix element
)
109 (add-extra-namespace element prefix uri
)))
110 (setf (namespace-declarations builder
) nil
)
111 (push element
(builder-nodes builder
))))
113 (defmethod sax:end-element
((builder builder
) uri lname qname
)
114 (declare (ignore uri lname qname
))
115 (pop (builder-nodes builder
)))
117 ;; zzz normalisieren?
118 (defmethod sax:characters
((builder builder
) data
)
119 (builder-append builder
(make-text data
)))
121 (defmethod sax:processing-instruction
((builder builder
) target data
)
122 (builder-append builder
(make-processing-instruction target data
)))
124 (defmethod sax:comment
((builder builder
) data
)
125 (builder-append builder
(make-comment data
)))
127 (defmethod sax:end-document
((builder builder
))
128 (pop (builder-nodes builder
)))