[s-xml-devel] Yet more complexity in resolve-identifier
Ben Hyde
bhyde at pobox.com
Wed Nov 1 01:38:47 UTC 2006
The trivial part of the following diff is avoiding the attempt to
call file-position on openmcl's string-input-streams.
The fun part changes the way that xml symbols are resolved so that
new schemes can be introduced; for example looking them up in a
dictionary.
Index: xml.lisp
===================================================================
RCS file: /project/s-xml/cvsroot/s-xml/src/xml.lisp,v
retrieving revision 1.16
diff -u -r1.16 xml.lisp
--- xml.lisp 31 Jan 2006 11:44:15 -0000 1.16
+++ xml.lisp 1 Nov 2006 01:29:50 -0000
@@ -28,8 +28,10 @@
"XML parser ~?~@[ near stream position ~d~]."
(xml-parser-error-message condition)
(xml-parser-error-args condition)
- (and (xml-parser-error-stream condition)
- (file-position (xml-parser-error-stream condition))))))
+ (let ((stream? (xml-parser-error-stream condition)))
+ (and stream?
+ #+openmcl(not (typep stream? 'ccl::string-input-stream))
+ (file-position stream?))))))
(:documentation "Thrown by the XML parser to indicate errorneous
input"))
(setf (documentation 'xml-parser-error-message 'function)
@@ -48,10 +50,10 @@
;; attribute parsing hooks
;; this is a bit complicated, refer to the mailing lists for a more
detailed explanation
-(defun parse-attribute-name (string)
+(defun parse-attribute-name (state string)
"Default parser for the attribute name"
(declare (special *namespaces*))
- (resolve-identifier string *namespaces* t))
+ (resolve-identifier state string *namespaces* t))
(defun parse-attribute-value (name string)
"Default parser for the attribute value"
@@ -248,7 +250,7 @@
(defvar *auto-export-symbols* t
"If t, export newly interned symbols form their packages")
-(defun resolve-identifier (identifier namespaces &optional as-
attribute)
+(defun default-resolve-identifier (identifier namespaces as-attribute)
"Resolve the string identifier in the list of namespace bindings"
(if *ignore-namespaces*
(intern identifier :keyword)
@@ -352,6 +354,11 @@
(mini-buffer :documentation "The secondary, smaller reusable
character buffer"
:accessor get-mini-buffer
:initform (make-extendable-string))
+ (resolve-identifier-hook
+ :documentation "Handle identifier strings as approprate given
current namespaces etc."
+ :accessor get-resolve-identifier-hook
+ :initarg :resolve-identifier-hook
+ :initform #'default-resolve-identifier)
(new-element-hook :documentation "Called when new element starts"
;; Handle the start of a new xml element with name and
attributes,
;; receiving seed from previous element (sibling or parent)
@@ -482,6 +489,10 @@
(t
(when (char/= char #\Null) (unread-char char stream))
(return identifier))))))
+
+(defmethod resolve-identifier ((state xml-parser-state) identifier
namespaces as-attribute)
+ (funcall (get-resolve-identifier-hook state)
+ identifier namespaces as-attribute))
(defun skip-comment (stream)
"Skip an XML comment in stream, positioned after the opening '<!--',
@@ -557,7 +568,7 @@
(when (zerop taglevel) (return))
(setf char (read-char stream nil #\Null))
(when (char= char #\Null)
- (error (parser-error "encountered unexpected eof for special (!
or ?) tag" nil stream)))
+ (error (parser-error "encountered unexpected eof for special (!
or ?) tag")))
(if (char/= string-delimiter #\Null)
;; inside a string we only look for a closing string delimiter
(when (char= char string-delimiter)
@@ -584,7 +595,7 @@
;; read the attribute key
(let ((key (let ((string (parse-identifier stream (get-mini-
buffer state))))
(if *ignore-namespaces*
- (funcall *attribute-name-parser* string)
+ (funcall *attribute-name-parser* state string)
(copy-seq string)))))
;; skip separating whitespace
(setf char (skip-whitespace stream))
@@ -610,19 +621,19 @@
(when (char= (peek-char nil stream nil #\Null) #\!)
(skip-special-tag stream state)
(return-from parse-xml-element))
- (let ((char #\Null) buffer open-tag parent-seed has-children)
+ (let ((char #\Null) buffer open-tag-text parent-seed has-children)
(declare (type character char))
(setf parent-seed (get-seed state))
;; read tag name (no whitespace between < and name ?)
- (setf open-tag (copy-seq (parse-identifier stream (get-mini-
buffer state))))
+ (setf open-tag-text (copy-seq (parse-identifier stream (get-mini-
buffer state))))
;; tag has been read, read attributes if any
(multiple-value-bind (attributes peeked-char)
(parse-xml-element-attributes stream state)
- (let ((*namespaces* (extend-namespaces attributes *namespaces*)))
- (setf open-tag (resolve-identifier open-tag *namespaces*))
+ (let* ((*namespaces* (extend-namespaces attributes *namespaces*))
+ (open-tag (resolve-identifier state open-tag-text *namespaces*
nil)))
(unless *ignore-namespaces*
(dolist (attribute attributes)
- (setf (car attribute) (funcall *attribute-name-parser*
(car attribute))
+ (setf (car attribute) (funcall *attribute-name-parser*
state (car attribute))
(cdr attribute) (funcall *attribute-value-parser*
(car attribute) (cdr attribute)))))
(setf (get-seed state) (funcall (get-new-element-hook state)
open-tag attributes (get-
seed state)))
@@ -657,8 +668,7 @@
(setf (get-seed state) (funcall (get-text-
hook state)
(copy-seq
buffer) (get-seed state))))
(read-char stream)
- (let ((close-tag (resolve-identifier (parse-
identifier stream (get-mini-buffer state))
-
*namespaces*)))
+ (let ((close-tag (resolve-identifier state
(parse-identifier stream (get-mini-buffer state)) *namespaces* nil)))
(unless (eq open-tag close-tag)
(error (parser-error "found <~a> not
matched by </~a> but by <~a>"
(list open-tag open-
tag close-tag) stream)))
More information about the s-xml-devel
mailing list