with-xml-output

While SAX events are useful, their generation is sometimes a little annoying, if you attempt to do it manually. So many functions to call! So many attributes to pass!

cxml includes a macro layer centered around CXML:WITH-XML-OUTPUT, which is more structured, and handles the SAX functions for you.

The most important macros and functions are:

CXML:WITH-XML-OUTPUT (handler) &body body macro
 
CXML:WITH-ELEMENT (qname) function
CXML:ATTRIBUTE (name value) function
CXML:TEXT (str) function
CXML:UNESCAPED (str) function
CXML:COMMENT (str) function

(Others which we won't go into here in detail are: CXML:DOCTYPE, CXML:WITH-NAMESPACE, CXML:WITH-ELEMENT*, and CXML:PROCESSING-INSTRUCTION.)

Example:

CL-USER> (cxml:with-xml-output (cxml:make-string-sink)
           (cxml:with-element "a"
             (cxml:attribute "a" 1)
             (cxml:attribute "b" "c")
             (cxml:text "d & e")))
 0: (SAX:START-DOCUMENT CXML::SINK)
 0: (SAX:START-ELEMENT CXML::SINK NIL "a" "a"
                            (#S(SAX::STANDARD-ATTRIBUTE)
                             #S(SAX::STANDARD-ATTRIBUTE)))
 0: (SAX:CHARACTERS CXML::SINK "t")
 0: (SAX:END-ELEMENT CXML::SINK NIL "a" "a")
 0: (SAX:END-DOCUMENT CXML::SINK)

"<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<a a=\"1\" b=\"c\">d &amp; e</a>"

Points to take away from this:

CL-USER> (cxml:with-xml-output (make-instance 'upcaser :chained-handler
                                              (stp:make-builder))
           (cxml:with-element "a"
             (cxml:attribute "a" 1)
             (cxml:attribute "b" "c")
             (cxml:text "d & e")))
#.(CXML-STP-IMPL::DOCUMENT
   :CHILDREN '(#.(CXML-STP:ELEMENT
                  :ATTRIBUTES '(#.(CXML-STP:ATTRIBUTE)
                                #.(CXML-STP:ATTRIBUTE))
                  :CHILDREN '(#.(CXML-STP:TEXT :DATA "D & E"))
                  :LOCAL-NAME "a")))