diff --git a/doc/html.xsl b/doc/html.xsl index f20af8b..cefd6bd 100644 --- a/doc/html.xsl +++ b/doc/html.xsl @@ -58,7 +58,9 @@ Klacks parser
- The following example illustrates creation of a klacks source, - use of the consume function to read individual events, - and shows some of the most common event types. + See below for examples.
-* (defparameter *source* (cxml:make-source "<example>text</example>")) -*SOURCE* -* (klacks:consume *source*) -:START-DOCUMENT -* (klacks:consume *source*) -:START-ELEMENT -NIL ;namespace URI -"example" ;local name -"example" ;qualified name -* (klacks:consume *source*) -:CHARACTERS -"text" -* (klacks:consume *source*) -:END-ELEMENT -NIL -"example" -"example" -* (klacks:consume *source*) -:END-DOCUMENT -* (klacks:consume *source*) -NIL
-
- Return the same values peek would, and in addition - advance the source forward to the next event. + Advance the source forward to the next event and returns it + like peek would.
Like peek, but return only the values, not the key.
++
+ Return the same values peek would, and in addition + advance the source forward to the next event. +
+
+
+
+
+ The following example illustrates creation of a klacks source, + use of the peek-next function to read individual events, + and shows some of the most common event types. +
+* (defparameter *source* (cxml:make-source "<example>text</example>")) +*SOURCE* + +* (klacks:peek-next *source*) +:START-DOCUMENT + +* (klacks:peek-next *source*) +:START-ELEMENT +NIL ;namespace URI +"example" ;local name +"example" ;qualified name + +* (klacks:peek-next *source*) +:CHARACTERS +"text" + +* (klacks:peek-next *source*) +:END-ELEMENT +NIL +"example" +"example" + +* (klacks:peek-next *source*) +:END-DOCUMENT + +* (klacks:peek-next *source*) +NIL+ +
+ In this example, find-element is used to skip over the + uninteresting events until the opening child1 tag is + found. Then serialize-element is used to generate SAX + events for the following element, including its children, and an + xmls-compatible list structure is build from those + events. find-element skips over whitespace, + and find-event is used to parse up + to :end-document, ensuring that the source has been + closed. +
+* (defparameter *source*
+ (cxml:make-source "<example>
+ <child1><p>foo</p></child1>
+ <child2 bar='baz'/>
+ </example>"))
+*SOURCE*
+
+* (klacks:find-element *source* "child1")
+:START-ELEMENT
+NIL
+"child1"
+"child1"
+
+* (klacks:serialize-element *source* (cxml-xmls:make-xmls-builder))
+("child1" NIL ("p" NIL "foo"))
+
+* (klacks:find-element *source*)
+:START-ELEMENT
+NIL
+"child2"
+"child2"
+
+* (klacks:serialize-element *source* (cxml-xmls:make-xmls-builder))
+("child2" (("bar" "baz")))
+
+* (klacks:find-event *source* :end-document)
+:END-DOCUMENT
+NIL
+NIL
+NIL
+
diff --git a/klacks/klacks-impl.lisp b/klacks/klacks-impl.lisp
index 2c5883a..7cd6027 100644
--- a/klacks/klacks-impl.lisp
+++ b/klacks/klacks-impl.lisp
@@ -79,6 +79,12 @@
(fill-source source)
(apply #'values current-values)))
+(defmethod klacks:peek-next ((source cxml-source))
+ (with-source (source current-key current-values)
+ (setf current-key nil)
+ (fill-source source)
+ (apply #'values current-key current-values)))
+
(defmethod klacks:consume ((source cxml-source))
(with-source (source current-key current-values)
(fill-source source)
diff --git a/klacks/klacks.lisp b/klacks/klacks.lisp
index 3d646a1..9ff4944 100644
--- a/klacks/klacks.lisp
+++ b/klacks/klacks.lisp
@@ -69,9 +69,9 @@
(check-type key (member :characters))
characters))
-(defun klacks:serialize-source (source handler)
- (loop
- (multiple-value-bind (key a b c) (klacks:peek source)
+(defun klacks:serialize-event (source handler)
+ (multiple-value-bind (key a b c) (klacks:peek source)
+ (let ((result nil))
(case key
(:start-document
(sax:start-document handler))
@@ -107,12 +107,66 @@
(:end-element
(sax:end-element handler a b c))
(:end-document
- (return (sax:end-document handler)))
+ (setf result (sax:end-document handler)))
+ ((nil)
+ (error "serialize-event read past end of document"))
(t
(error "unexpected klacks key: ~A" key)))
- (klacks:consume source))))
+ (klacks:consume source)
+ result)))
(defun serialize-declaration-kludge (list handler)
(loop
for (fn . args) in list
do (apply fn handler args)))
+
+(defun klacks:serialize-source (source handler)
+ (loop
+ (let ((document (klacks:serialize-event source handler)))
+ (when document
+ (return document)))))
+
+(defun klacks:serialize-element (source handler &key (document-events t))
+ (unless (eq (klacks:peek source) :start-element)
+ (error "not at start of element"))
+ (when document-events
+ (sax:start-document handler))
+ (labels ((recurse ()
+ (klacks:serialize-event source handler)
+ (loop
+ (let ((key (klacks:peek source)))
+ (ecase key
+ (:start-element (recurse))
+ (:end-element (return))
+ ((:characters :comment :processing-instruction)
+ (klacks:serialize-event source handler)))))
+ (klacks:serialize-event source handler)))
+ (recurse))
+ (when document-events
+ (sax:end-document handler)))
+
+(defun klacks:find-element (source &optional lname uri)
+ (loop
+ (multiple-value-bind (key current-uri current-lname current-qname)
+ (klacks:peek-next source)
+ (case key
+ ((nil)
+ (return nil))
+ (:start-element
+ (when (and (eq key :start-element)
+ (or (null lname)
+ (equal lname (klacks:current-lname source)))
+ (or (null uri)
+ (equal uri (klacks:current-uri source))))
+ (return
+ (values key current-uri current-lname current-qname))))))))
+
+(defun klacks:find-event (source key)
+ (loop
+ (multiple-value-bind (this a b c)
+ (klacks:peek-next source)
+ (cond
+ ((null this)
+ (return nil))
+ ((eq this key)
+ (return (values this a b c)))))))
diff --git a/klacks/package.lisp b/klacks/package.lisp
index 124071e..276ef13 100644
--- a/klacks/package.lisp
+++ b/klacks/package.lisp
@@ -24,6 +24,11 @@
#:peek
#:peek-value
+ #:peek-next
+ #:consume
+
+ #:find-element
+ #:find-event
#:map-attributes
#:list-attributes
@@ -33,6 +38,6 @@
#:current-characters
#:current-cdata-section-p
- #:consume
-
+ #:serialize-event
+ #:serialize-element
#:serialize-source))