klacks:get-attribute; dribbling source fix; FAQ
This commit is contained in:
@ -63,10 +63,15 @@ body {
|
|||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1,h2,h3 {
|
h1 {
|
||||||
margin-left: -30px;
|
margin-left: -30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h2,h3 {
|
||||||
|
margin-left: -30px;
|
||||||
|
margin-top: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
background-color: #eeeeee;
|
background-color: #eeeeee;
|
||||||
border: solid 1px #d0d0d0;
|
border: solid 1px #d0d0d0;
|
||||||
|
|||||||
26
doc/html.xsl
26
doc/html.xsl
@ -8,7 +8,7 @@
|
|||||||
<xsl:copy>
|
<xsl:copy>
|
||||||
<xsl:apply-templates select="@*|node()"/>
|
<xsl:apply-templates select="@*|node()"/>
|
||||||
</xsl:copy>
|
</xsl:copy>
|
||||||
</xsl:template>
|
</xsl:template>
|
||||||
|
|
||||||
<xsl:template match="documentation">
|
<xsl:template match="documentation">
|
||||||
<html>
|
<html>
|
||||||
@ -38,7 +38,7 @@
|
|||||||
<li>
|
<li>
|
||||||
<ul class="hack">
|
<ul class="hack">
|
||||||
<li>
|
<li>
|
||||||
<a href="quickstart.html"><b>Quick-Start Example</b></a>
|
<a href="quickstart.html"><b>Quick-Start Example / FAQ</b></a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
@ -85,4 +85,26 @@
|
|||||||
</html>
|
</html>
|
||||||
</xsl:template>
|
</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>
|
</xsl:stylesheet>
|
||||||
|
|||||||
@ -48,8 +48,15 @@
|
|||||||
information</a>).
|
information</a>).
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<h3>See also</h3>
|
||||||
|
<p>
|
||||||
|
Relax NG validation is available as a separate
|
||||||
|
project: <a href="">cxml-rng</a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
<a name="changes"/>
|
<a name="changes"/>
|
||||||
<h2>Recent Changes</h2>
|
<h3>Recent Changes</h3>
|
||||||
<p class="nomargin"><tt>rel-2007-xx-yy</tt></p>
|
<p class="nomargin"><tt>rel-2007-xx-yy</tt></p>
|
||||||
<ul class="nomargin">
|
<ul class="nomargin">
|
||||||
<li>xml:base support (SAX and Klacks only, not yet used in DOM).
|
<li>xml:base support (SAX and Klacks only, not yet used in DOM).
|
||||||
|
|||||||
@ -1,56 +1,247 @@
|
|||||||
<documentation title="CXML Quick-Start Example">
|
<documentation title="CXML Quick-Start Example">
|
||||||
<h1>Quick-Start Example</h1>
|
<h1>Quick-Start Example / FAQ</h1>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Make sure to <a href="installation.html#installation">install and load</a> cxml first.
|
Make sure to <a href="installation.html#installation">install and load</a> cxml first.
|
||||||
</p>
|
</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)
|
<pre>* <b>(with-open-file (s "example.xml" :direction :output)
|
||||||
(write-string "<test a='b'><child/></test>" s))</b></pre>
|
(write-string "<test a='b'><child/></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
|
<p>Parse <tt>example.xml</tt> into a DOM tree (<a href="sax.html#parser">read
|
||||||
more</a>):</p>
|
more</a>):</p>
|
||||||
<pre>* <b>(cxml:parse-file "example.xml" (cxml-dom:make-dom-builder))</b>
|
<pre>* <b>(cxml:parse-file "example.xml" (cxml-dom:make-dom-builder))</b>
|
||||||
#<DOM-IMPL::DOCUMENT @ #x72206172>
|
#<DOM-IMPL::DOCUMENT @ #x72206172>
|
||||||
|
|
||||||
;; save result for later:
|
;; save result for later:
|
||||||
* <b>(defparameter *example* *)</b>
|
* <b>(defparameter *example* *)</b>
|
||||||
*EXAMPLE*</pre>
|
*EXAMPLE*</pre>
|
||||||
|
|
||||||
|
<heading>Using DOM</heading>
|
||||||
|
|
||||||
<p>Inspect the DOM tree (<a href="sax.html#dom">read more</a>):</p>
|
<p>Inspect the DOM tree (<a href="sax.html#dom">read more</a>):</p>
|
||||||
<pre>* <b>(dom:document-element *example*)</b>
|
<pre>* <b>(dom:document-element *example*)</b>
|
||||||
#<DOM-IMPL::ELEMENT test @ #x722b6ba2>
|
#<DOM-IMPL::ELEMENT test @ #x722b6ba2>
|
||||||
* <b>(dom:tag-name (dom:document-element *example*))</b>
|
|
||||||
|
* (<b>dom:tag-name</b> (dom:document-element *example*))
|
||||||
"test"
|
"test"
|
||||||
* <b>(dom:child-nodes (dom:document-element *example*))</b>
|
|
||||||
|
* (<b>dom:child-nodes</b> (dom:document-element *example*))
|
||||||
#(#<DOM-IMPL::ELEMENT child @ #x722b6d8a>)
|
#(#<DOM-IMPL::ELEMENT child @ #x722b6d8a>)
|
||||||
* <b>(dom:get-attribute (dom:document-element *example*) "a")</b>
|
|
||||||
|
* (<b>dom:get-attribute</b> (dom:document-element *example*) <b>"a"</b>)
|
||||||
"b"</pre>
|
"b"</pre>
|
||||||
|
|
||||||
|
<heading>Serializing DOM</heading>
|
||||||
|
|
||||||
<p>Serialize the DOM document back into a file (<a
|
<p>Serialize the DOM document back into a file (<a
|
||||||
href="sax.html#serialization">read more</a>):</p>
|
href="sax.html#serialization">read more</a>):</p>
|
||||||
<pre><b>(with-open-file (out "example.out" :direction :output :element-type '(unsigned-byte 8))
|
<pre>(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>
|
<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
|
<p>As an alternative to DOM, parse into xmls-compatible list
|
||||||
structure (<a href="xmls-compat.html">read more</a>):</p>
|
structure (<a href="xmls-compat.html">read more</a>):</p>
|
||||||
<pre>* <b>(cxml:parse-file "example.xml" (cxml-xmls:make-xmls-builder))</b>
|
<pre>* <b>(cxml:parse-file "example.xml" (cxml-xmls:make-xmls-builder))</b>
|
||||||
("test" (("a" "b")) ("child" NIL))</pre>
|
("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
|
<p>Use klacks to read events from the parser incrementally. The
|
||||||
following example looks only for :start-element and :end-element
|
following example looks only for :start-element and :end-element
|
||||||
events and prints them (<a href="klacks.html">read more</a>):</p>
|
events and prints them (<a href="klacks.html">read more</a>):</p>
|
||||||
<pre>* <b>(klacks:with-open-source
|
<pre>* <b>(klacks:with-open-source
|
||||||
(s (cxml:make-source #p"example.xml"))
|
(s (cxml:make-source #p"example.xml"))</b>
|
||||||
(loop
|
(loop
|
||||||
for key = (klacks:peek s)
|
for key = <b>(klacks:peek s)</b>
|
||||||
while key
|
while key
|
||||||
do
|
do
|
||||||
(case key
|
(case key
|
||||||
(:start-element
|
(:start-element
|
||||||
(format t "~A {" (klacks:current-qname s)))
|
(format t "~A {" <b>(klacks:current-qname s)</b>))
|
||||||
(:end-element
|
(:end-element
|
||||||
(format t "}")))
|
(format t "}")))
|
||||||
(klacks:consume s)))</b>
|
<b>(klacks:consume s)</b>))
|
||||||
test {child {}}</pre>
|
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><foo xyz="abc">
|
||||||
|
<bar blub="bla"></bar>
|
||||||
|
Hi there.
|
||||||
|
</foo></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><!DOCTYPE test SYSTEM 'http://www.lichteblau.com/blubba/dtdexample.dtd'>
|
||||||
|
<test a='b'>blub<child/></test></pre>
|
||||||
|
|
||||||
|
<a href="http://www.lichteblau.com/blubba/dtdexample.dtd">
|
||||||
|
<tt>dtdexample.dtd</tt></a>:
|
||||||
|
<pre><!ELEMENT test (#PCDATA|child)*>
|
||||||
|
<!ATTLIST test
|
||||||
|
a CDATA #REQUIRED
|
||||||
|
>
|
||||||
|
|
||||||
|
<!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>
|
</documentation>
|
||||||
|
|||||||
@ -102,6 +102,13 @@
|
|||||||
(sax:attribute-value a)
|
(sax:attribute-value a)
|
||||||
(sax:attribute-specified-p 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))
|
(defmethod klacks:list-attributes ((source cxml-source))
|
||||||
(slot-value source 'current-attributes))
|
(slot-value source 'current-attributes))
|
||||||
|
|
||||||
|
|||||||
@ -34,13 +34,13 @@
|
|||||||
|
|
||||||
(defgeneric klacks:map-attributes (fn source))
|
(defgeneric klacks:map-attributes (fn source))
|
||||||
(defgeneric klacks:list-attributes (source))
|
(defgeneric klacks:list-attributes (source))
|
||||||
|
(defgeneric klacks:get-attribute (source lname &optional uri))
|
||||||
;;;(defgeneric klacks:current-uri (source))
|
;;;(defgeneric klacks:current-uri (source))
|
||||||
;;;(defgeneric klacks:current-lname (source))
|
;;;(defgeneric klacks:current-lname (source))
|
||||||
;;;(defgeneric klacks:current-qname (source))
|
;;;(defgeneric klacks:current-qname (source))
|
||||||
;;;(defgeneric klacks:current-characters (source))
|
;;;(defgeneric klacks:current-characters (source))
|
||||||
(defgeneric klacks:current-cdata-section-p (source))
|
(defgeneric klacks:current-cdata-section-p (source))
|
||||||
(defgeneric klacks:map-current-namespace-declarations (fn 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-line-number (source))
|
||||||
(defgeneric klacks:current-column-number (source))
|
(defgeneric klacks:current-column-number (source))
|
||||||
|
|||||||
@ -37,6 +37,7 @@
|
|||||||
|
|
||||||
#:map-attributes
|
#:map-attributes
|
||||||
#:list-attributes
|
#:list-attributes
|
||||||
|
#:get-attribute
|
||||||
#:current-uri
|
#:current-uri
|
||||||
#:current-lname
|
#:current-lname
|
||||||
#:current-qname
|
#:current-qname
|
||||||
|
|||||||
@ -26,7 +26,8 @@
|
|||||||
(defclass klacks:tapping-source (klacks:source)
|
(defclass klacks:tapping-source (klacks:source)
|
||||||
((upstream-source :initarg :upstream-source :accessor upstream-source)
|
((upstream-source :initarg :upstream-source :accessor upstream-source)
|
||||||
(dribble-handler :initarg :dribble-handler :accessor dribble-handler)
|
(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)
|
(defmethod initialize-instance :after ((instance klacks:tapping-source) &key)
|
||||||
(let ((s-p (make-instance 'klacksax :source (upstream-source instance))))
|
(let ((s-p (make-instance 'klacksax :source (upstream-source instance))))
|
||||||
@ -36,7 +37,9 @@
|
|||||||
;;; event dribbling
|
;;; event dribbling
|
||||||
|
|
||||||
(defun maybe-dribble (source)
|
(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)
|
(klacks:serialize-event (upstream-source source)
|
||||||
(dribble-handler source)
|
(dribble-handler source)
|
||||||
:consume nil)
|
:consume nil)
|
||||||
|
|||||||
Reference in New Issue
Block a user