uri-to-pathname angepasst, decode in path (z.b. %20)
[cxml.git] / doc / quickstart.xml
blobf5f626b692e519fc96a4f95926e72234491c0342
1 <documentation title="CXML Quick-Start Example">
2     <h1>Quick-Start Example / FAQ</h1>
4     <p>
5       Make sure to <a href="installation.html#installation">install and load</a> cxml first.
6     </p>
8     <h3>
9       On this page
10     </h3>      
11     <page-index/>
12     
13     <p>
14       To try the following examples, create a test file
15       called <tt>example.xml</tt>:
16     </p>
17     <pre>* <b>(with-open-file (s "example.xml" :direction :output)
18     (write-string "&lt;test a='b'&gt;&lt;child/&gt;&lt;/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
23     more</a>):</p>
24     <pre>* <b>(cxml:parse-file "example.xml" (cxml-dom:make-dom-builder))</b>
25 #&lt;DOM-IMPL::DOCUMENT @ #x72206172>
27 ;; save result for later:
28 * <b>(defparameter *example* *)</b>
29 *EXAMPLE*</pre>
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 #&lt;DOM-IMPL::ELEMENT test @ #x722b6ba2&gt;
37 * (<b>dom:tag-name</b> (dom:document-element *example*))
38 "test"
40 * (<b>dom:child-nodes</b> (dom:document-element *example*))
41 #(#&lt;DOM-IMPL::ELEMENT child @ #x722b6d8a&gt;)
43 * (<b>dom:get-attribute</b> (dom:document-element *example*) <b>"a"</b>)
44 "b"</pre>
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>
55     <p>
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
61       handlers.
62     </p>
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>
69     <p>
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>.
73     </p>
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>
86   (loop
87       for key = <b>(klacks:peek s)</b>
88       while key
89       do
90         (case key
91           (:start-element
92             (format t "~A {" <b>(klacks:current-qname s)</b>))
93           (:end-element
94             (format t "}")))
95         <b>(klacks:consume s)</b>))
96 test {child {}}</pre>
98     <heading>Writing XML</heading>
100     <p>
101       Serialization is always done using sinks, which accept SAX events,
102       but there are convenience functions and macros to make that easier
103       to use:
104     </p>
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>
111    <p>
112       Prints this to <tt>stream</tt>:
113    </p>
114    <pre>&lt;foo xyz="abc"&gt;
115   &lt;bar blub="bla"&gt;&lt;/bar&gt;
116   Hi there.
117 &lt;/foo&gt;</pre>
118     
119     <heading>Help! CXML says 'URI scheme :HTTP not supported'</heading>
121     <p>
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.
126     </p>
128     <p>
129       The are several solutions to this, covered in detail below:
130       <ul>
131         <li>
132           Load the DTD/entity from local files using an entity resolver
133         </li>
134         <li>
135           Skip parsing of the DTD/entity entirely by pretending it is
136           empty, again using an entity resolver.
137         </li>
138         <li>
139           Use a <em>catalog</em> to make CXML find DTDs in the local
140           filesystem automatically.
141         </li>
142         <li>
143           Teach CXML actually load DTDs using HTTP.
144         </li>
145       </ul>
146     </p>
148     <p>
149       Here are the example files for the following solutions to this
150       problem:
151     </p>
153     <a href="http://www.lichteblau.com/blubba/dtdexample.xml">
154       <tt>dtdexample.xml</tt>:</a>
155     <pre>&lt;!DOCTYPE test SYSTEM 'http://www.lichteblau.com/blubba/dtdexample.dtd'>
156 &lt;test a='b'>blub&lt;child/>&lt;/test></pre>
157     
158     <a href="http://www.lichteblau.com/blubba/dtdexample.dtd">
159       <tt>dtdexample.dtd</tt></a>:
160     <pre>&lt;!ELEMENT test (#PCDATA|child)*>
161 &lt;!ATTLIST test
162   a CDATA #REQUIRED
163   >
165 &lt;!ELEMENT child EMPTY>
166 </pre>
168     <heading>Loading DTDs from local files</heading>
170     <p>
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:
174     </p>
175     
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>
187     <p>
188       Yes and no.
189     </p>
190     <p>
191       <i>Yes</i>, you can force CXML to do this, see the following example.
192     </p>
193     
194     <p>
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
198       attributes.
199     </p>
201     <p>
202       The trick to make CXML skip the DTD is to pretend that it is empty
203       by returning a zero-length stream instead:
204     </p>
205     
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>
211     <heading>
212       Catalogs: How can I use the HTML DTD installed by my distribution?
213     </heading>
215     <p>
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.
218     </p>
219     <p>
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
224       points to.
225     </p>
226     <p>By default, CXML looks for the catalog in /etc/xml/catalog
227     (Linux) and /usr/local/share/xml/catalog.ports (FreeBSD).
228     </p>
229     <pre>* <b>(setf cxml:*catalog* (cxml:make-catalog))</b>
230 * (cxml:parse-file "test.xhtml" (cxml-dom:make-dom-builder))</pre>
232     <heading>
233       Can I load DTDs through HTTP?
234     </heading>
236     <p>
237       Sure, just use an entity-resolver function that does it.
238     </p>
239     <p>
240       Install <a href="http://weitz.de/drakma/">Drakma</a> and try this:
241     </p>
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>
247 </documentation>