Added new functions attribute*, unparse-attribute, and macro with-element*,

with-namespace* to the SAX generation wrapper API.
This commit is contained in:
dlichteblau
2007-05-01 20:06:59 +00:00
parent dd833309bf
commit 41ee5ae24d
4 changed files with 84 additions and 21 deletions

View File

@ -509,13 +509,17 @@
(defvar *current-element*)
(defvar *sink*)
(defvar *unparse-namespace-bindings*)
(defvar *current-namespace-bindings*)
(defmacro with-xml-output (sink &body body)
`(invoke-with-xml-output (lambda () ,@body) ,sink))
(defun invoke-with-xml-output (fn sink)
(let ((*sink* sink)
(*current-element* nil))
(*current-element* nil)
(*unparse-namespace-bindings* *initial-namespace-bindings*)
(*current-namespace-bindings* nil))
(sax:start-document *sink*)
(funcall fn)
(sax:end-document *sink*)))
@ -523,37 +527,86 @@
(defmacro with-element (qname &body body)
`(invoke-with-element (lambda () ,@body) ,qname))
(defmacro with-element* ((prefix lname) &body body)
`(invoke-with-element* (lambda () ,@body) ,prefix ,lname))
(defmacro with-namespace ((prefix uri) &body body)
`(invoke-with-namespace (lambda () ,@body) ,prefix ,uri))
(defun maybe-emit-start-tag ()
(when *current-element*
;; starting child node, need to emit opening tag of parent first:
(destructuring-bind (qname &rest attributes) *current-element*
(sax:start-element *sink* nil nil qname (reverse attributes)))
(destructuring-bind ((uri lname qname) &rest attributes) *current-element*
(sax:start-element *sink* uri lname qname (reverse attributes)))
(setf *current-element* nil)))
(defun invoke-with-namespace (fn prefix uri)
(let ((*unparse-namespace-bindings*
(acons prefix uri *unparse-namespace-bindings*))
(*current-namespace-bindings*
(acons prefix uri *current-namespace-bindings*)))
(sax:start-prefix-mapping *sink* prefix uri)
(multiple-value-prog1
(funcall fn)
(sax:end-prefix-mapping *sink* prefix))))
(defun invoke-with-element (fn qname)
(setf qname (rod qname))
(multiple-value-bind (prefix lname)
(split-qname qname)
(invoke-with-element* fn prefix lname qname)))
(defun find-unparse-namespace (prefix)
(cdr (assoc prefix *unparse-namespace-bindings* :test 'equal)))
(defun invoke-with-element* (fn prefix lname &optional qname)
(setf prefix (when prefix (rod prefix)))
(setf lname (rod lname))
(maybe-emit-start-tag)
(let ((*current-element* (list qname)))
(let* ((qname (or qname
(if prefix (concatenate 'rod prefix #":" lname) lname)))
(uri (find-unparse-namespace (or prefix #"")))
(*current-element*
(cons (list uri lname qname)
(mapcar (lambda (x)
(destructuring-bind (prefix &rest uri) x
(sax:make-attribute
:namespace-uri #"http://www.w3.org/2000/xmlns/"
:local-name prefix
:qname (if (zerop (length prefix))
#"xmlns"
(concatenate 'rod #"xmlns:" prefix))
:value uri)))
*current-namespace-bindings*))))
(multiple-value-prog1
(funcall fn)
(let ((*current-namespace-bindings* nil))
(funcall fn))
(maybe-emit-start-tag)
(sax:end-element *sink* nil nil qname))))
(sax:end-element *sink* uri lname qname))))
(defun attribute-1 (name value)
(push (sax:make-attribute :qname (rod name) :value (rod value))
(cdr *current-element*))
value)
(defgeneric unparse-attribute (value))
(defmethod unparse-attribute ((value string)) value)
(defmethod unparse-attribute ((value null)) nil)
(defmethod unparse-attribute ((value integer)) (write-to-string value))
(defgeneric attribute (name value))
(defun attribute (qname value)
(setf qname (rod qname))
(multiple-value-bind (prefix lname)
(split-qname qname)
(attribute* prefix lname value qname)))
(defmethod attribute (name (value string))
(attribute-1 name value))
(defmethod attribute (name (value null))
(declare (ignore name)))
(defmethod attribute (name (value integer))
(attribute-1 name (write-to-string value)))
(defun attribute* (prefix lname value &optional qname)
(setf value (unparse-attribute value))
(when value
(setf prefix (when prefix (rod prefix)))
(setf lname (rod lname))
(push (sax:make-attribute
:namespace-uri (find-unparse-namespace prefix)
:local-name lname
:qname (or qname
(if prefix (concatenate 'rod prefix #":" lname) lname))
:value (rod value))
(cdr *current-element*))))
(defun cdata (data)
(maybe-emit-start-tag)