klacks:get-attribute; dribbling source fix; FAQ

This commit is contained in:
dlichteblau
2007-05-01 18:21:40 +00:00
parent b8ba07a919
commit dd833309bf
8 changed files with 258 additions and 22 deletions

View File

@ -63,10 +63,15 @@ body {
background-repeat: no-repeat;
}
h1,h2,h3 {
h1 {
margin-left: -30px;
}
h2,h3 {
margin-left: -30px;
margin-top: 2em;
}
pre {
background-color: #eeeeee;
border: solid 1px #d0d0d0;

View File

@ -4,11 +4,11 @@
doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN"
doctype-system="http://www.w3.org/TR/html4/loose.dtd"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="documentation">
<html>
@ -38,7 +38,7 @@
<li>
<ul class="hack">
<li>
<a href="quickstart.html"><b>Quick-Start Example</b></a>
<a href="quickstart.html"><b>Quick-Start Example / FAQ</b></a>
</li>
</ul>
</li>
@ -85,4 +85,26 @@
</html>
</xsl:template>
<xsl:template match="page-index">
<ul>
<xsl:for-each select="//heading">
<li>
<a href="#{generate-id()}">
<xsl:copy>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</a>
</li>
</xsl:for-each>
</ul>
</xsl:template>
<xsl:template match="heading">
<a name="{generate-id()}"/>
<h3>
<xsl:copy>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</h3>
</xsl:template>
</xsl:stylesheet>

View File

@ -48,8 +48,15 @@
information</a>).
</p>
<h3>See also</h3>
<p>
Relax NG validation is available as a separate
project: <a href="">cxml-rng</a>.
</p>
<a name="changes"/>
<h2>Recent Changes</h2>
<h3>Recent Changes</h3>
<p class="nomargin"><tt>rel-2007-xx-yy</tt></p>
<ul class="nomargin">
<li>xml:base support (SAX and Klacks only, not yet used in DOM).

View File

@ -1,56 +1,247 @@
<documentation title="CXML Quick-Start Example">
<h1>Quick-Start Example</h1>
<h1>Quick-Start Example / FAQ</h1>
<p>
Make sure to <a href="installation.html#installation">install and load</a> cxml first.
</p>
<p>Create a test file called <tt>example.xml</tt>:</p>
<h3>
On this page
</h3>
<page-index/>
<p>
To try the following examples, create a test file
called <tt>example.xml</tt>:
</p>
<pre>* <b>(with-open-file (s "example.xml" :direction :output)
(write-string "&lt;test a='b'&gt;&lt;child/&gt;&lt;/test>" s))</b></pre>
<heading>Parsing a file</heading>
<p>Parse <tt>example.xml</tt> into a DOM tree (<a href="sax.html#parser">read
more</a>):</p>
<pre>* <b>(cxml:parse-file "example.xml" (cxml-dom:make-dom-builder))</b>
#&lt;DOM-IMPL::DOCUMENT @ #x72206172>
;; save result for later:
* <b>(defparameter *example* *)</b>
*EXAMPLE*</pre>
<heading>Using DOM</heading>
<p>Inspect the DOM tree (<a href="sax.html#dom">read more</a>):</p>
<pre>* <b>(dom:document-element *example*)</b>
#&lt;DOM-IMPL::ELEMENT test @ #x722b6ba2&gt;
* <b>(dom:tag-name (dom:document-element *example*))</b>
* (<b>dom:tag-name</b> (dom:document-element *example*))
"test"
* <b>(dom:child-nodes (dom:document-element *example*))</b>
* (<b>dom:child-nodes</b> (dom:document-element *example*))
#(#&lt;DOM-IMPL::ELEMENT child @ #x722b6d8a&gt;)
* <b>(dom:get-attribute (dom:document-element *example*) "a")</b>
* (<b>dom:get-attribute</b> (dom:document-element *example*) <b>"a"</b>)
"b"</pre>
<heading>Serializing DOM</heading>
<p>Serialize the DOM document back into a file (<a
href="sax.html#serialization">read more</a>):</p>
<pre><b>(with-open-file (out "example.out" :direction :output :element-type '(unsigned-byte 8))
(dom:map-document (cxml:make-octet-stream-sink out) *example*))</b></pre>
<pre>(with-open-file (out "example.out" :direction :output :element-type '(unsigned-byte 8))
<b>(dom:map-document (cxml:make-octet-stream-sink out) *example*)</b></pre>
<heading>Parsing into XMLS-like lists</heading>
<p>
If DOM is not the representation you want to you, parsing into
other data structures is possible using the same SAX parser
function, while using a different handler.
The XMLS builder is included for compatibility with XMLS, and also
also sample code (see cxml/xml/xmls-compat.lisp) for your own
handlers.
</p>
<p>As an alternative to DOM, parse into xmls-compatible list
structure (<a href="xmls-compat.html">read more</a>):</p>
<pre>* <b>(cxml:parse-file "example.xml" (cxml-xmls:make-xmls-builder))</b>
("test" (("a" "b")) ("child" NIL))</pre>
<p>
Again, serialization into XML is done using a sink as a SAX
handler and a data-structure specific function to generate SAX
events for the document, in this case <tt>cxml-xmls:map-node</tt>.
</p>
<pre>* (with-open-file (out "example.out" :direction :output :element-type '(unsigned-byte 8))
(<b>cxml-xmls:map-node (cxml:make-octet-stream-sink out)
'("test" (("a" "b")) ("child" nil)))</b>)</pre>
<heading>Parsing incrementally using Klacks</heading>
<p>Use klacks to read events from the parser incrementally. The
following example looks only for :start-element and :end-element
events and prints them (<a href="klacks.html">read more</a>):</p>
<pre>* <b>(klacks:with-open-source
(s (cxml:make-source #p"example.xml"))
(s (cxml:make-source #p"example.xml"))</b>
(loop
for key = (klacks:peek s)
for key = <b>(klacks:peek s)</b>
while key
do
(case key
(:start-element
(format t "~A {" (klacks:current-qname s)))
(format t "~A {" <b>(klacks:current-qname s)</b>))
(:end-element
(format t "}")))
(klacks:consume s)))</b>
<b>(klacks:consume s)</b>))
test {child {}}</pre>
<heading>Writing XML</heading>
<p>
Serialization is always done using sinks, which accept SAX events,
but there are convenience functions and macros to make that easier
to use:
</p>
<pre>(cxml:with-xml-output (cxml:make-octet-stream-sink stream :indentation 2 :canonical nil)
(cxml:with-element "foo"
(cxml:attribute "xyz" "abc")
(cxml:with-element "bar"
(cxml:attribute "blub" "bla"))
(cxml:text "Hi there.")))</pre>
<p>
Prints this to <tt>stream</tt>:
</p>
<pre>&lt;foo xyz="abc"&gt;
&lt;bar blub="bla"&gt;&lt;/bar&gt;
Hi there.
&lt;/foo&gt;</pre>
<heading>Help! CXML says 'URI scheme :HTTP not supported'</heading>
<p>
By default, this error will occur when the DTD (or generally, any
entity) has an http:// URL as its system ID. CXML itself
understands only file:// URLs, but allows users to customize the
behaviour for all URLs.
</p>
<p>
The are several solutions to this, covered in detail below:
<ul>
<li>
Load the DTD/entity from local files using an entity resolver
</li>
<li>
Skip parsing of the DTD/entity entirely by pretending it is
empty, again using an entity resolver.
</li>
<li>
Use a <em>catalog</em> to make CXML find DTDs in the local
filesystem automatically.
</li>
<li>
Teach CXML actually load DTDs using HTTP.
</li>
</ul>
</p>
<p>
Here are the example files for the following solutions to this
problem:
</p>
<a href="http://www.lichteblau.com/blubba/dtdexample.xml">
<tt>dtdexample.xml</tt>:</a>
<pre>&lt;!DOCTYPE test SYSTEM 'http://www.lichteblau.com/blubba/dtdexample.dtd'>
&lt;test a='b'>blub&lt;child/>&lt;/test></pre>
<a href="http://www.lichteblau.com/blubba/dtdexample.dtd">
<tt>dtdexample.dtd</tt></a>:
<pre>&lt;!ELEMENT test (#PCDATA|child)*>
&lt;!ATTLIST test
a CDATA #REQUIRED
>
&lt;!ELEMENT child EMPTY>
</pre>
<heading>Loading DTDs from local files</heading>
<p>
Use the :entity-resolver argument to <tt>parse-file</tt> to
specify a function that maps System IDs and Public IDs to local
files of your choice:
</p>
<pre>(let ((uri "http://www.lichteblau.com/blubba/dtdexample.dtd")
(pathname "dtdexample.dtd"))
(flet ((resolver (pubid sysid)
(declare (ignore pubid))
<b>(when (puri:uri= sysid (puri:parse-uri uri))
(open pathname :element-type '(unsigned-byte 8)))</b>))
(cxml:parse-file "dtdexample.xml" (cxml-dom:make-dom-builder) <b>:entity-resolver #'resolver</b>)))</pre>
<heading>Can I skip loading of DTDs entirely?</heading>
<p>
Yes and no.
</p>
<p>
<i>Yes</i>, you can force CXML to do this, see the following example.
</p>
<p>
But no, skipping the DTD will not actually work if the document
references entities declared in the DTD, especially since neither
SAX nor DOM are able to report unresolved entity references in
attributes.
</p>
<p>
The trick to make CXML skip the DTD is to pretend that it is empty
by returning a zero-length stream instead:
</p>
<pre>(flet ((resolver (pubid sysid)
(declare (ignore pubid sysid))
<b>(flexi-streams:make-in-memory-input-stream nil)</b>))
(cxml:parse-file "dtdexample.xml" (cxml-dom:make-dom-builder) <b>:entity-resolver #'resolver</b>))</pre>
<heading>
Catalogs: How can I use the HTML DTD installed by my distribution?
</heading>
<p>
Rather than writing an entity resolver function yourself, CXML can
use XML catalogs to find DTDs and entity files on your local system.
</p>
<p>
Catalogs are particularly helpful for DTDs that are
pre-installed. For example, most Linux distributions include a
package for the XHTML DTD. The DTD will reside in a
distribution-dependent location, which the central catalog file
points to.
</p>
<p>By default, CXML looks for the catalog in /etc/xml/catalog
(Linux) and /usr/local/share/xml/catalog.ports (FreeBSD).
</p>
<pre>* <b>(setf cxml:*catalog* (cxml:make-catalog))</b>
* (cxml:parse-file "test.xhtml" (cxml-dom:make-dom-builder))</pre>
<heading>
Can I load DTDs through HTTP?
</heading>
<p>
Sure, just use an entity-resolver function that does it.
</p>
<p>
Install <a href="http://weitz.de/drakma/">Drakma</a> and try this:
</p>
<pre>(flet ((resolver (pubid sysid)
(declare (ignore pubid))
<b>(when (eq (puri:uri-scheme sysid) :http)
(drakma:http-request sysid :want-stream t))</b>))
(cxml:parse-file "dtdexample.xml" (cxml-dom:make-dom-builder) <b>:entity-resolver #'resolver</b>))</pre>
</documentation>

View File

@ -102,6 +102,13 @@
(sax:attribute-value a)
(sax:attribute-specified-p a))))
(defmethod klacks:get-attribute
((source cxml-source) lname &optional uri)
(dolist (a (slot-value source 'current-attributes))
(when (and (equal (sax:attribute-local-name a) lname)
(equal (sax:attribute-namespace-uri a) uri))
(return (sax:attribute-value a)))))
(defmethod klacks:list-attributes ((source cxml-source))
(slot-value source 'current-attributes))

View File

@ -34,13 +34,13 @@
(defgeneric klacks:map-attributes (fn source))
(defgeneric klacks:list-attributes (source))
(defgeneric klacks:get-attribute (source lname &optional uri))
;;;(defgeneric klacks:current-uri (source))
;;;(defgeneric klacks:current-lname (source))
;;;(defgeneric klacks:current-qname (source))
;;;(defgeneric klacks:current-characters (source))
(defgeneric klacks:current-cdata-section-p (source))
(defgeneric klacks:map-current-namespace-declarations (fn source))
(defgeneric klacks:map-previous-namespace-declarations (fn source))
(defgeneric klacks:current-line-number (source))
(defgeneric klacks:current-column-number (source))

View File

@ -37,6 +37,7 @@
#:map-attributes
#:list-attributes
#:get-attribute
#:current-uri
#:current-lname
#:current-qname

View File

@ -26,7 +26,8 @@
(defclass klacks:tapping-source (klacks:source)
((upstream-source :initarg :upstream-source :accessor upstream-source)
(dribble-handler :initarg :dribble-handler :accessor dribble-handler)
(seen-event-p :initform nil :accessor seen-event-p)))
(seen-event-p :initform nil :accessor seen-event-p)
(document-done-p :initform nil :accessor document-done-p)))
(defmethod initialize-instance :after ((instance klacks:tapping-source) &key)
(let ((s-p (make-instance 'klacksax :source (upstream-source instance))))
@ -36,7 +37,9 @@
;;; event dribbling
(defun maybe-dribble (source)
(unless (seen-event-p source)
(unless (or (seen-event-p source) (document-done-p source))
(when (eq (klacks:peek (upstream-source source)) :end-document)
(setf (document-done-p source) t))
(klacks:serialize-event (upstream-source source)
(dribble-handler source)
:consume nil)