1 <documentation title="CXML Quick-Start Example">
2 <h1>Quick-Start Example / FAQ</h1>
5 Make sure to <a href="installation.html#installation">install and load</a> cxml first.
14 To try the following examples, create a test file
15 called <tt>example.xml</tt>:
17 <pre>* <b>(with-open-file (s "example.xml" :direction :output)
18 (write-string "<test a='b'><child/></test>" s))</b></pre>
20 <heading>Parsing a file</heading>
22 <p>Parse <tt>example.xml</tt> into a DOM tree (<a href="sax.html#parser">read
24 <pre>* <b>(cxml:parse-file "example.xml" (cxml-dom:make-dom-builder))</b>
25 #<DOM-IMPL::DOCUMENT @ #x72206172>
27 ;; save result for later:
28 * <b>(defparameter *example* *)</b>
31 <heading>Using DOM</heading>
33 <p>Inspect the DOM tree (<a href="sax.html#dom">read more</a>):</p>
34 <pre>* <b>(dom:document-element *example*)</b>
35 #<DOM-IMPL::ELEMENT test @ #x722b6ba2>
37 * (<b>dom:tag-name</b> (dom:document-element *example*))
40 * (<b>dom:child-nodes</b> (dom:document-element *example*))
41 #(#<DOM-IMPL::ELEMENT child @ #x722b6d8a>)
43 * (<b>dom:get-attribute</b> (dom:document-element *example*) <b>"a"</b>)
46 <heading>Serializing DOM</heading>
48 <p>Serialize the DOM document back into a file (<a
49 href="sax.html#serialization">read more</a>):</p>
50 <pre>(with-open-file (out "example.out" :direction :output :element-type '(unsigned-byte 8))
51 <b>(dom:map-document (cxml:make-octet-stream-sink out) *example*)</b></pre>
53 <heading>Parsing into XMLS-like lists</heading>
56 If DOM is not the representation you want to you, parsing into
57 other data structures is possible using the same SAX parser
58 function, while using a different handler.
59 The XMLS builder is included for compatibility with XMLS, and also
60 also sample code (see cxml/xml/xmls-compat.lisp) for your own
64 <p>As an alternative to DOM, parse into xmls-compatible list
65 structure (<a href="xmls-compat.html">read more</a>):</p>
66 <pre>* <b>(cxml:parse-file "example.xml" (cxml-xmls:make-xmls-builder))</b>
67 ("test" (("a" "b")) ("child" NIL))</pre>
70 Again, serialization into XML is done using a sink as a SAX
71 handler and a data-structure specific function to generate SAX
72 events for the document, in this case <tt>cxml-xmls:map-node</tt>.
75 <pre>* (with-open-file (out "example.out" :direction :output :element-type '(unsigned-byte 8))
76 (<b>cxml-xmls:map-node (cxml:make-octet-stream-sink out)
77 '("test" (("a" "b")) ("child" nil)))</b>)</pre>
79 <heading>Parsing incrementally using Klacks</heading>
81 <p>Use klacks to read events from the parser incrementally. The
82 following example looks only for :start-element and :end-element
83 events and prints them (<a href="klacks.html">read more</a>):</p>
84 <pre>* <b>(klacks:with-open-source
85 (s (cxml:make-source #p"example.xml"))</b>
87 for key = <b>(klacks:peek s)</b>
92 (format t "~A {" <b>(klacks:current-qname s)</b>))
95 <b>(klacks:consume s)</b>))
98 <heading>Writing XML</heading>
101 Serialization is always done using sinks, which accept SAX events,
102 but there are convenience functions and macros to make that easier
105 <pre>(cxml:with-xml-output (cxml:make-octet-stream-sink stream :indentation 2 :canonical nil)
106 (cxml:with-element "foo"
107 (cxml:attribute "xyz" "abc")
108 (cxml:with-element "bar"
109 (cxml:attribute "blub" "bla"))
110 (cxml:text "Hi there.")))</pre>
112 Prints this to <tt>stream</tt>:
114 <pre><foo xyz="abc">
115 <bar blub="bla"></bar>
119 <heading>Help! CXML says 'URI scheme :HTTP not supported'</heading>
122 By default, this error will occur when the DTD (or generally, any
123 entity) has an http:// URL as its system ID. CXML itself
124 understands only file:// URLs, but allows users to customize the
125 behaviour for all URLs.
129 The are several solutions to this, covered in detail below:
132 Load the DTD/entity from local files using an entity resolver
135 Skip parsing of the DTD/entity entirely by pretending it is
136 empty, again using an entity resolver.
139 Use a <em>catalog</em> to make CXML find DTDs in the local
140 filesystem automatically.
143 Teach CXML actually load DTDs using HTTP.
149 Here are the example files for the following solutions to this
153 <a href="http://www.lichteblau.com/blubba/dtdexample.xml">
154 <tt>dtdexample.xml</tt>:</a>
155 <pre><!DOCTYPE test SYSTEM 'http://www.lichteblau.com/blubba/dtdexample.dtd'>
156 <test a='b'>blub<child/></test></pre>
158 <a href="http://www.lichteblau.com/blubba/dtdexample.dtd">
159 <tt>dtdexample.dtd</tt></a>:
160 <pre><!ELEMENT test (#PCDATA|child)*>
165 <!ELEMENT child EMPTY>
168 <heading>Loading DTDs from local files</heading>
171 Use the :entity-resolver argument to <tt>parse-file</tt> to
172 specify a function that maps System IDs and Public IDs to local
173 files of your choice:
176 <pre>(let ((uri "http://www.lichteblau.com/blubba/dtdexample.dtd")
177 (pathname "dtdexample.dtd"))
178 (flet ((resolver (pubid sysid)
179 (declare (ignore pubid))
180 <b>(when (puri:uri= sysid (puri:parse-uri uri))
181 (open pathname :element-type '(unsigned-byte 8)))</b>))
182 (cxml:parse-file "dtdexample.xml" (cxml-dom:make-dom-builder) <b>:entity-resolver #'resolver</b>)))</pre>
185 <heading>Can I skip loading of DTDs entirely?</heading>
191 <i>Yes</i>, you can force CXML to do this, see the following example.
195 But no, skipping the DTD will not actually work if the document
196 references entities declared in the DTD, especially since neither
197 SAX nor DOM are able to report unresolved entity references in
202 The trick to make CXML skip the DTD is to pretend that it is empty
203 by returning a zero-length stream instead:
206 <pre>(flet ((resolver (pubid sysid)
207 (declare (ignore pubid sysid))
208 <b>(flexi-streams:make-in-memory-input-stream nil)</b>))
209 (cxml:parse-file "dtdexample.xml" (cxml-dom:make-dom-builder) <b>:entity-resolver #'resolver</b>))</pre>
212 Catalogs: How can I use the HTML DTD installed by my distribution?
216 Rather than writing an entity resolver function yourself, CXML can
217 use XML catalogs to find DTDs and entity files on your local system.
220 Catalogs are particularly helpful for DTDs that are
221 pre-installed. For example, most Linux distributions include a
222 package for the XHTML DTD. The DTD will reside in a
223 distribution-dependent location, which the central catalog file
226 <p>By default, CXML looks for the catalog in /etc/xml/catalog
227 (Linux) and /usr/local/share/xml/catalog.ports (FreeBSD).
229 <pre>* <b>(setf cxml:*catalog* (cxml:make-catalog))</b>
230 * (cxml:parse-file "test.xhtml" (cxml-dom:make-dom-builder))</pre>
233 Can I load DTDs through HTTP?
237 Sure, just use an entity-resolver function that does it.
240 Install <a href="http://weitz.de/drakma/">Drakma</a> and try this:
242 <pre>(flet ((resolver (pubid sysid)
243 (declare (ignore pubid))
244 <b>(when (eq (puri:uri-scheme sysid) :http)
245 (drakma:http-request sysid :want-stream t))</b>))
246 (cxml:parse-file "dtdexample.xml" (cxml-dom:make-dom-builder) <b>:entity-resolver #'resolver</b>))</pre>