various docstrings; release
This commit is contained in:
committed by
David Lichteblau
parent
a1a95a4d03
commit
3aada6fb89
3
cxml.asd
3
cxml.asd
@ -45,7 +45,8 @@
|
||||
(:file "xmlns-normalizer" :depends-on ("xml-parse"))
|
||||
(:file "space-normalizer" :depends-on ("xml-parse"))
|
||||
(:file "catalog" :depends-on ("xml-parse"))
|
||||
(:file "sax-proxy" :depends-on ("xml-parse")))
|
||||
(:file "sax-proxy" :depends-on ("xml-parse"))
|
||||
(:file "atdoc-configuration" :depends-on ("package")))
|
||||
:depends-on (:closure-common :puri #-scl :trivial-gray-streams))
|
||||
|
||||
(defclass utf8dom-file (closure-source-file) ((of)))
|
||||
|
||||
41
dist.sh
41
dist.sh
@ -1,8 +1,10 @@
|
||||
#!/bin/sh
|
||||
#!/bin/sh -e
|
||||
set -x
|
||||
|
||||
cd $(dirname $0)
|
||||
home=$(pwd)
|
||||
name=$(basename $home)
|
||||
dir=${name}-$(date --iso)
|
||||
name_and_date=${name}-$(date --iso)
|
||||
|
||||
TMPDIR=`mktemp -d /tmp/dist.XXXXXXXXXX`
|
||||
cleanup() {
|
||||
@ -11,13 +13,36 @@ cleanup() {
|
||||
}
|
||||
trap cleanup exit
|
||||
|
||||
make -C doc
|
||||
|
||||
git tag -f $name_and_date
|
||||
git archive --prefix=$name_and_date/ $name_and_date | \
|
||||
( cd $TMPDIR && tar xvf - )
|
||||
|
||||
# echo '(progn (load "dist.lisp") (quit))' | clbuild lisp
|
||||
|
||||
rsync -a doc $TMPDIR/$name_and_date
|
||||
|
||||
cd $TMPDIR
|
||||
cvs -d "`cat $home/CVS/Root`" export -r HEAD -d "$dir" "$name"
|
||||
|
||||
make -C $dir/doc
|
||||
|
||||
tgz=$TMPDIR/${dir}.tgz
|
||||
tar czf $tgz $dir
|
||||
tgz=$TMPDIR/${name_and_date}.tgz
|
||||
tar czf $tgz $name_and_date
|
||||
gpg -b -a $tgz
|
||||
|
||||
mv $tgz $tgz.asc $home/
|
||||
mkdir -p ~/clnet/project/cxml/public_html/
|
||||
|
||||
rsync -av \
|
||||
$name_and_date/doc/ \
|
||||
~/clnet/project/cxml/public_html/
|
||||
|
||||
rsync $tgz $tgz.asc ~/clnet/project/cxml/public_html/download/
|
||||
|
||||
rm -f ~/clnet/project/cxml/public_html/download/cxml.tar.gz
|
||||
rm -f ~/clnet/project/cxml/public_html/download/cxml.tar.gz.asc
|
||||
|
||||
ln -sf ${name_and_date}.tgz ~/clnet/project/cxml/public_html/download/cxml.tar.gz
|
||||
ln -sf ${name_and_date}.tgz.asc ~/clnet/project/cxml/public_html/download/cxml.tar.gz.asc
|
||||
|
||||
echo done
|
||||
exit 0
|
||||
rsync -av ~/bob/public_html bob.askja.de
|
||||
|
||||
@ -2,5 +2,5 @@ all: dom.html index.html installation.html klacks.html quickstart.html sax.html
|
||||
|
||||
%.html: %.xml html.xsl
|
||||
xsltproc html.xsl $< >$@.tmp
|
||||
mv $@.tmp $@
|
||||
mv -f $@.tmp $@
|
||||
chmod -w $@
|
||||
|
||||
120
doc/html.xsl
120
doc/html.xsl
@ -20,66 +20,66 @@
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
</head>
|
||||
<body>
|
||||
<div class="sidebar">
|
||||
<div class="sidebar-title">
|
||||
<a href="index.html">Closure XML</a>
|
||||
</div>
|
||||
<div class="sidebar-main">
|
||||
<ul class="main">
|
||||
<li>
|
||||
<a href="installation.html">Installing Closure XML</a>
|
||||
<ul class="sub">
|
||||
<li><a href="installation.html#download"><b>Download</b></a></li>
|
||||
<li><a href="installation.html#implementations">Implementation-specific notes</a></li>
|
||||
<li><a href="installation.html#compilation">Compilation</a></li>
|
||||
<li><a href="installation.html#tests">Tests</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<ul class="hack">
|
||||
<li>
|
||||
<a href="quickstart.html"><b>Quick-Start Example / FAQ</b></a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<a href="sax.html">SAX parsing and serialization</a>
|
||||
<ul class="sub">
|
||||
<li><a href="sax.html#parser">Parsing and Validating</a></li>
|
||||
<li><a href="sax.html#serialization">Serialization</a></li>
|
||||
<li><a href="sax.html#misc">Miscellaneous SAX handlers</a></li>
|
||||
<li><a href="sax.html#rods">Recoders</a></li>
|
||||
<li><a href="sax.html#dtdcache">Caching of DTD Objects</a></li>
|
||||
<li><a href="sax.html#catalogs">XML Catalogs</a></li>
|
||||
<li><a href="sax.html#sax">SAX Interface</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<a href="klacks.html">Klacks parser</a>
|
||||
<ul class="sub">
|
||||
<li><a href="klacks.html#sources">Parsing incrementally</a></li>
|
||||
<li><a href="klacks.html#convenience">Convenience functions</a></li>
|
||||
<li><a href="klacks.html#klacksax">Bridging Klacks and SAX</a></li>
|
||||
<li><a href="klacks.html#locator">Location information</a></li>
|
||||
<li><a href="klacks.html#klacksax">Examples</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<a href="dom.html">DOM implementation</a>
|
||||
<ul class="sub">
|
||||
<li><a href="dom.html#parser">Parsing with the DOM builder</a></li>
|
||||
<li><a href="dom.html#serialization">Serialization</a></li>
|
||||
<li><a href="dom.html#mapping">DOM/Lisp mapping</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<ul class="hack">
|
||||
<li><a href="xmls-compat.html">XMLS Builder</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar">
|
||||
<div class="sidebar-title">
|
||||
<a href="index.html">Closure XML</a>
|
||||
</div>
|
||||
<div class="sidebar-main">
|
||||
<ul class="main">
|
||||
<li>
|
||||
<a href="installation.html">Installing Closure XML</a>
|
||||
<ul class="sub">
|
||||
<li><a href="installation.html#download"><b>Download</b></a></li>
|
||||
<li><a href="installation.html#implementations">Implementation-specific notes</a></li>
|
||||
<li><a href="installation.html#compilation">Compilation</a></li>
|
||||
<li><a href="installation.html#tests">Tests</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<ul class="hack">
|
||||
<li>
|
||||
<a href="quickstart.html"><b>Quick-Start Example / FAQ</b></a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<a href="sax.html">SAX parsing and serialization</a>
|
||||
<ul class="sub">
|
||||
<li><a href="sax.html#parser">Parsing and Validating</a></li>
|
||||
<li><a href="sax.html#serialization">Serialization</a></li>
|
||||
<li><a href="sax.html#misc">Miscellaneous SAX handlers</a></li>
|
||||
<li><a href="sax.html#rods">Recoders</a></li>
|
||||
<li><a href="sax.html#dtdcache">Caching of DTD Objects</a></li>
|
||||
<li><a href="sax.html#catalogs">XML Catalogs</a></li>
|
||||
<li><a href="sax.html#sax">SAX Interface</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<a href="klacks.html">Klacks parser</a>
|
||||
<ul class="sub">
|
||||
<li><a href="klacks.html#sources">Parsing incrementally</a></li>
|
||||
<li><a href="klacks.html#convenience">Convenience functions</a></li>
|
||||
<li><a href="klacks.html#klacksax">Bridging Klacks and SAX</a></li>
|
||||
<li><a href="klacks.html#locator">Location information</a></li>
|
||||
<li><a href="klacks.html#klacksax">Examples</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<a href="dom.html">DOM implementation</a>
|
||||
<ul class="sub">
|
||||
<li><a href="dom.html#parser">Parsing with the DOM builder</a></li>
|
||||
<li><a href="dom.html#serialization">Serialization</a></li>
|
||||
<li><a href="dom.html#mapping">DOM/Lisp mapping</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<ul class="hack">
|
||||
<li><a href="xmls-compat.html">XMLS Builder</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<xsl:apply-templates/>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -70,7 +70,7 @@
|
||||
Please refer to the <a href="installation.html#download">
|
||||
installation instructions</a> for details.
|
||||
</div>
|
||||
<p class="nomargin"><tt>rel-2008-xx-yy</tt></p>
|
||||
<p class="nomargin"><tt>rel-2008-11-30</tt></p>
|
||||
<ul class="nomargin">
|
||||
<li>
|
||||
Support for user-specified output encodings
|
||||
|
||||
7
xml/atdoc-configuration.lisp
Normal file
7
xml/atdoc-configuration.lisp
Normal file
@ -0,0 +1,7 @@
|
||||
(in-package :cxml)
|
||||
|
||||
(defun atdoc-directory ()
|
||||
"doc/atdoc/")
|
||||
|
||||
(defun atdoc-title ()
|
||||
"Closure XML")
|
||||
@ -11,19 +11,62 @@
|
||||
(defclass broadcast-handler (sax:abstract-handler)
|
||||
((handlers :initform nil
|
||||
:initarg :handlers
|
||||
:accessor broadcast-handler-handlers)))
|
||||
:accessor broadcast-handler-handlers))
|
||||
(:documentation
|
||||
"A SAX handler which passes every event it receives on to each of several
|
||||
chained handlers, somewhat similar to the way a @foo{broadcast-stream}
|
||||
works.
|
||||
|
||||
You can subclass @foo{broadcast-handler} to modify the events
|
||||
before they are being passed on. Define methods on your handler
|
||||
class for the events to be modified. All other events will pass
|
||||
through to the chained handlers unmodified.
|
||||
|
||||
Broadcast handler functions return the result of calling the event
|
||||
function on the last handler in the list. In particular,
|
||||
the overall result from @foo{sax:end-document} will be ignored
|
||||
for all other handlers.
|
||||
|
||||
@see-slot{broadcast-handler-handlers}"))
|
||||
|
||||
(setf (documentation #'broadcast-handler-handlers 'function)
|
||||
"@arg[instance]{A @class{broadcast-handler}}
|
||||
@return{A list of @class{SAX handler}s.}
|
||||
|
||||
Returns the list of SAX handlers that arechained to this broadcast
|
||||
handler.")
|
||||
|
||||
(defun make-broadcast-handler (&rest handlers)
|
||||
"@arg[handlers]{A list of @class{SAX handler}s.}
|
||||
@return{A @class{broadcast-handler}.}
|
||||
|
||||
Creates a SAX handler which passes every event it receives on to each
|
||||
handler specified as an argument to this function.
|
||||
|
||||
See @class{broadcast-handler} for details. "
|
||||
(make-instance 'broadcast-handler :handlers handlers))
|
||||
|
||||
(defclass sax-proxy (broadcast-handler)
|
||||
())
|
||||
()
|
||||
(:documentation
|
||||
"@class{sax-proxy} is a subclass of @class{broadcast-handler} which
|
||||
sends events to exactly one chained handler.
|
||||
|
||||
This class is still included for compatibility with older versions of
|
||||
CXML which did not include the more general @class{broadcast-handler}
|
||||
yet, but has been retrofitted as a subclass of the latter.
|
||||
|
||||
@see-slot{proxy-chained-handler}"))
|
||||
|
||||
(defmethod initialize-instance
|
||||
:after ((instance sax-proxy) &key chained-handler)
|
||||
(setf (proxy-chained-handler instance) chained-handler))
|
||||
|
||||
(defmethod proxy-chained-handler ((instance sax-proxy))
|
||||
"@arg[instance]{A @class{sax-proxy}.}
|
||||
@return{A @class{SAX handler}s.}
|
||||
|
||||
Returns the SAX handler that is chained to this SAX proxy."
|
||||
(car (broadcast-handler-handlers instance)))
|
||||
|
||||
(defmethod (setf proxy-chained-handler) (newval (instance sax-proxy))
|
||||
|
||||
275
xml/unparse.lisp
275
xml/unparse.lisp
@ -142,13 +142,108 @@
|
||||
stream))
|
||||
|
||||
#+rune-is-character
|
||||
(defun make-string-sink (&rest args) (apply #'make-rod-sink args))
|
||||
(defun make-string-sink (&rest args)
|
||||
"@return{A serialization sink, i.e. a @class{SAX handler}}
|
||||
|
||||
Returns a handler that writes processes SAX events by writing an
|
||||
equivalent XML document to a newly allocated string of unicode
|
||||
characters.
|
||||
|
||||
The sink will return the string as a result from
|
||||
@fun{sax:end-document}.
|
||||
|
||||
All sink creation functions share the same keyword arguments.
|
||||
Refer to @fun{make-octet-vector-sink} for details on keyword
|
||||
arguments."
|
||||
(apply #'make-rod-sink args))
|
||||
|
||||
|
||||
(defmethod sax:end-document ((sink sink))
|
||||
(close-ystream (sink-ystream sink)))
|
||||
|
||||
|
||||
(setf (documentation #'make-octet-vector-sink 'function)
|
||||
"@arg[canonical]{canonical form, one of NIL, T, 1, 2. If specified,
|
||||
serialization in canonical form is enabled. The two canonical
|
||||
forms are useful to allow comparisons of XML documents and their
|
||||
content model by character-by-character comparisons of
|
||||
their serialized representation.}
|
||||
@arg[indentation]{indentation level. An integer or nil. If
|
||||
specified, a pretty-printing indentation mode is enabled. Note
|
||||
that indentation as implemented currently changes the content model
|
||||
unconditionally, and is usually helpful only for debugging purposes.}
|
||||
@arg[encoding]{the character encoding to use. A string or
|
||||
keyword. Values are interpreted by Babel. nil is also allowed
|
||||
and means UTF-8.}
|
||||
@arg[omit-xml-declaration]{Boolean. If true, no XML declaration
|
||||
is written.}
|
||||
@return{A serialization sink, i.e. a @class{SAX handler}}
|
||||
|
||||
Returns a handler that writes processes SAX events by writing an
|
||||
equivalent XML document to a newly allocated vector of
|
||||
@code{(unsigned-byte 8)}.
|
||||
|
||||
The following values for @code{canonical} are allowed:
|
||||
|
||||
@begin{itemize}
|
||||
@item{t or 1: Canonical XML}
|
||||
@item{2: Second Canonical Form}
|
||||
@item{NIL: Use a more readable non-canonical representation.}
|
||||
@end{itemize}
|
||||
|
||||
The sink will return the vector as a result from
|
||||
@fun{sax:end-document}.
|
||||
|
||||
An internal subset will be included in the result regardless of the
|
||||
canonical setting. It is the responsibility of the caller to not
|
||||
report an internal subset for canonical <= 1, or only notations as
|
||||
required for canonical = 2. For example, the include-doctype argument
|
||||
to dom:map-document should be set to nil for the former behaviour and
|
||||
:canonical-notations for the latter. ")
|
||||
|
||||
(setf (documentation #'make-octet-stream-sink 'function)
|
||||
"@arg[stream]{An (unsigned-byte 8) stream.}
|
||||
@return{A serialization sink, i.e. a @class{SAX handler}}
|
||||
|
||||
Returns a handler that writes processes SAX events by writing an
|
||||
equivalent XML document to @var{stream}.
|
||||
|
||||
The sink will return @var{stream} as a result from
|
||||
@fun{sax:end-document}.
|
||||
|
||||
All sink creation functions share the same keyword arguments.
|
||||
Refer to @fun{make-octet-vector-sink} for details on keyword
|
||||
arguments.")
|
||||
|
||||
(setf (documentation #'make-rod-sink 'function)
|
||||
"@return{A serialization sink, i.e. a @class{SAX handler}}
|
||||
|
||||
Returns a handler that writes processes SAX events by writing an
|
||||
equivalent XML document to a newly allocated string of unicode
|
||||
characters (or on implementations without unicode support: a rod).
|
||||
|
||||
The sink will return the string (or rod) as a result from
|
||||
@fun{sax:end-document}.
|
||||
|
||||
All sink creation functions share the same keyword arguments.
|
||||
Refer to @fun{make-octet-vector-sink} for details on keyword
|
||||
arguments.")
|
||||
|
||||
(setf (documentation #'make-character-stream-sink 'function)
|
||||
"@arg[stream]{A character stream.}
|
||||
@return{A serialization sink, i.e. a @class{SAX handler}}
|
||||
|
||||
Returns a handler that writes processes SAX events by writing an
|
||||
equivalent XML document to @var{stream}.
|
||||
|
||||
The sink will return @var{stream} as a result from
|
||||
@fun{sax:end-document}.
|
||||
|
||||
All sink creation functions share the same keyword arguments.
|
||||
Refer to @fun{make-octet-vector-sink} for details on keyword
|
||||
arguments.")
|
||||
|
||||
|
||||
;;;; doctype and notations
|
||||
|
||||
(defmethod sax:start-document ((sink sink))
|
||||
@ -627,9 +722,54 @@
|
||||
(defvar *current-namespace-bindings*)
|
||||
|
||||
(defmacro with-xml-output (sink &body body)
|
||||
"@arg[sink]{A @class{SAX handler}, evaluated}
|
||||
@arg[body]{forms}
|
||||
@return{The result of calling @code{sax:end-document} on @code{sink}.}
|
||||
|
||||
Evaluates sink and establishes it as the current output sink for
|
||||
the following \"convenience serialization\" macros and functions:
|
||||
@fun{with-element}, @fun{with-namespace}, @fun{doctype},
|
||||
@fun{with-element*}, @fun{attribute}, @fun{attribute*}, @fun{text}
|
||||
@fun{comment}, @fun{processing-instruction}, @fun{unescaped}.
|
||||
|
||||
Before @code{body} is evaluated, @fun{sax:start-document} is signalled
|
||||
to the @code{sink}. Afterwards, @fun{sax:end-document} is signalled.
|
||||
|
||||
Note that convenience serialization delays some serialization events.
|
||||
For example, @fun{with-element} delays signalling an opening tag
|
||||
using @fun{sax:start-element} until it has information about all
|
||||
possible attributes of the element. Because of this delay, it is
|
||||
not usually safe to signal SAX events to the sink during the extent
|
||||
of @code{with-xml-output}. However, @fun{with-output-sink} can be
|
||||
used to force output of delayed events, allowing direct use of the
|
||||
sink.
|
||||
|
||||
Example:
|
||||
@pre{(with-xml-output (make-octet-stream-sink stream)
|
||||
(with-element \"foo\"
|
||||
(attribute \"xyz\" \"abc\")
|
||||
(with-element \"bar\"
|
||||
(attribute \"blub\" \"bla\"))
|
||||
(text \"Hi there.\")))}"
|
||||
`(invoke-with-xml-output (lambda () ,@body) ,sink))
|
||||
|
||||
(defmacro with-output-sink ((var) &body body)
|
||||
"@arg[var]{A symbol, not evaluated.}
|
||||
@arg[body]{forms, an implicit progn}
|
||||
@return{The result of @code{body}.}
|
||||
|
||||
Allows safe use of manual calls to SAX functions during the extent
|
||||
of @fun{with-xml-output},
|
||||
|
||||
Determines the current output sink established by @fun{with-xml-output},
|
||||
as used by convenience serialization functions. Writes delayed
|
||||
serialization events to the sink. Binds local variable @code{var} to the
|
||||
sink and evaluates @code{body} as an implicit progn.
|
||||
|
||||
The consequences are undefined if this macro is used outside of the
|
||||
extent of a call to @fun{with-xml-output}.
|
||||
|
||||
See @fun{with-xml-output} for details on delayed events."
|
||||
`(invoke-with-output-sink (lambda (,var) ,@body)))
|
||||
|
||||
(defun invoke-with-xml-output (fn sink)
|
||||
@ -646,15 +786,74 @@
|
||||
(funcall fn *sink*))
|
||||
|
||||
(defmacro with-element (qname &body body)
|
||||
"@arg[qname]{A string, evaluated.}
|
||||
@arg[body]{forms, an implicit progn}
|
||||
@return{The result of @code{body}.}
|
||||
|
||||
Writes an element to the current output sink.
|
||||
|
||||
This macro is a convenience wrapper around @fun{with-element*}.
|
||||
|
||||
@var{qname} is parsed to determine the element's namespace prefix
|
||||
and local name. Then @fun{with-element*} is called on @var{body} using
|
||||
the resulting values."
|
||||
`(invoke-with-element (lambda () ,@body) ,qname))
|
||||
|
||||
(defmacro with-element* ((prefix lname) &body body)
|
||||
"@arg[prefix]{Namespace prefix, a string (evaluated).}
|
||||
@arg[lname]{Local name, a string (evaluated).}
|
||||
@arg[body]{forms, an implicit progn}
|
||||
@return{The result of @code{body}.}
|
||||
|
||||
Writes an element to the current output sink.
|
||||
|
||||
First, @var{prefix} is resolved to a namespace URI using the bindings
|
||||
established by @fun{with-namespace}.
|
||||
|
||||
Next, body is evaluated as an implicit progn. During this time,
|
||||
attributes for the element can be specified using @fun{attribute}.
|
||||
|
||||
Once information on the start tag is complete, @fun{start-element}
|
||||
on the current output sink, using the specified namespace prefix and
|
||||
local name specified by the arguments, the namespace URI computed as
|
||||
described above,and including all attributes collected so far.
|
||||
|
||||
Information on the start tag is considered complete once the first of
|
||||
the following situations occurs:
|
||||
@begin{itemize}
|
||||
@item{Before any child node of the element is written, e.g. using an
|
||||
inner call of @fun{with-element},}
|
||||
@item{Before the body of @fun{with-ouptut-sink} is evaluated.}
|
||||
@item{After the end of @var{body} has been reached.}
|
||||
@end{itemize}
|
||||
|
||||
Finally, sax:end-element is used to write an end tag, using the same
|
||||
qualified name and namespace information as above."
|
||||
`(invoke-with-element* (lambda () ,@body) ,prefix ,lname))
|
||||
|
||||
(defmacro with-namespace ((prefix uri) &body body)
|
||||
"@arg[prefix]{Namespace prefix, a string (evaluated).}
|
||||
@arg[uri]{Namespace URI, a string (evaluated).}
|
||||
@arg[body]{forms, an implicit progn}
|
||||
@return{The result of @code{body}.}
|
||||
|
||||
Registers @code{prefix} as a name for the namespace URI @code{uri}
|
||||
for the extent of body.
|
||||
|
||||
Namespace bindings established by @code{with-namespace} are used by
|
||||
@fun{with-element} and @fun{with-element*} as well as @fun{attribute}
|
||||
and @fun{attribute*}."
|
||||
`(invoke-with-namespace (lambda () ,@body) ,prefix ,uri))
|
||||
|
||||
(defun doctype (name public-id system-id &optional internal-subset)
|
||||
"@arg[name]{Element name, a string.}
|
||||
@arg[public-id]{String}
|
||||
@arg[system-id]{A system ID as a @class{puri:uri}.}
|
||||
@arg[internal-subset]{nil or a string}
|
||||
@return{undocumented}
|
||||
|
||||
Writes a doctype declaration to the current output sink, using the
|
||||
specified name, public ID, system ID, and optionally an internal subset."
|
||||
(sax:start-dtd *sink* name public-id system-id)
|
||||
(when internal-subset
|
||||
(sax:unparsed-internal-subset *sink* internal-subset))
|
||||
@ -717,12 +916,43 @@
|
||||
(defmethod unparse-attribute ((value integer)) (write-to-string value))
|
||||
|
||||
(defun attribute (qname value)
|
||||
"@arg[qname]{Qualified name, a string.}
|
||||
@arg[value]{Any value understood by @fun{unparse-attribute}, in particular
|
||||
strings.}
|
||||
@return{undocumented}
|
||||
|
||||
Collects an attribute for the start tag that is currently being written.
|
||||
|
||||
This function may only be called during the extent of a use of
|
||||
@fun{with-element} or @fun{with-element*}, and only before the first
|
||||
child node has been written.
|
||||
|
||||
An attribute for the current element is recorded using the namespace prefix
|
||||
and local name specified by @var{qname}. The attribute's namespace prefix
|
||||
is resolved to a namespace URI using the bindings established by
|
||||
@fun{with-namespace},and that namespace URI is used for the attribute."
|
||||
(setf qname (rod qname))
|
||||
(multiple-value-bind (prefix lname)
|
||||
(split-qname qname)
|
||||
(attribute* prefix lname value qname)))
|
||||
|
||||
(defun attribute* (prefix lname value &optional qname)
|
||||
"@arg[prefix]{Namespace prefix, a string.}
|
||||
@arg[lname]{Local name, a string.}
|
||||
@arg[value]{Any value understood by @fun{unparse-attribute}, in particular
|
||||
strings.}
|
||||
@return{undocumented}
|
||||
|
||||
Collects an attribute for the start tag that is currently being written.
|
||||
|
||||
This function may only be called during the extent of a use of
|
||||
@fun{with-element} or @fun{with-element*}, and only before the first
|
||||
child node has been written.
|
||||
|
||||
An attribute for the current element is recorded using the namespace prefix
|
||||
and local name specified by arguments. @var{prefix} is resolved to a
|
||||
namespace URI using the bindings established by @fun{with-namespace},
|
||||
and that namespace URI is used for the attribute."
|
||||
(setf value (unparse-attribute value))
|
||||
(when value
|
||||
(setf prefix (when prefix (rod prefix)))
|
||||
@ -736,6 +966,14 @@
|
||||
(cdr *current-element*))))
|
||||
|
||||
(defun cdata (data)
|
||||
"@arg[data]{String.}
|
||||
@return{undocumented}
|
||||
|
||||
Writes a CDATA section to the current output sink, using @code{data} as
|
||||
its contents.
|
||||
|
||||
Note: It is currently the caller's responsibily to ensure that the CDATA
|
||||
section will not contain forbidden character sequences."
|
||||
(maybe-emit-start-tag)
|
||||
(sax:start-cdata *sink*)
|
||||
(sax:characters *sink* (rod data))
|
||||
@ -743,20 +981,55 @@
|
||||
data)
|
||||
|
||||
(defun text (data)
|
||||
"@arg[data]{String.}
|
||||
@return{undocumented}
|
||||
|
||||
Writes a text node to the current output sink, using @code{data} as
|
||||
its contents.
|
||||
|
||||
Note: It is currently the caller's responsibily to ensure that @code{data}
|
||||
does not contain characters forbidden for character data."
|
||||
(maybe-emit-start-tag)
|
||||
(sax:characters *sink* (rod data))
|
||||
data)
|
||||
|
||||
(defun comment (data)
|
||||
"@arg[data]{String.}
|
||||
@return{undocumented}
|
||||
|
||||
Writes a comment to the current output sink, using @code{data} as
|
||||
its contents.
|
||||
|
||||
Note: It is currently the caller's responsibily to ensure that @code{data}
|
||||
does not contain character sequences forbidden for comments."
|
||||
(maybe-emit-start-tag)
|
||||
(sax:comment *sink* (rod data))
|
||||
data)
|
||||
|
||||
(defun processing-instruction (target data)
|
||||
"@arg[target]{String.}
|
||||
@arg[data]{String.}
|
||||
@return{undocumented}
|
||||
|
||||
Writes a processing instruction to the current output sink, using
|
||||
@code{target} and @code{data} as its contents.
|
||||
|
||||
Note: It is currently the caller's responsibily to ensure that
|
||||
@code{target} and @code{data} do not contain character sequences
|
||||
forbidden for processing instruction contents."
|
||||
(maybe-emit-start-tag)
|
||||
(sax:processing-instruction *sink* (rod target) (rod data))
|
||||
data)
|
||||
|
||||
(defun unescaped (str)
|
||||
"@arg[data]{String.}
|
||||
@return{undocumented}
|
||||
|
||||
If supported by the current output sink, writes character data directly
|
||||
to the sink's target.
|
||||
|
||||
Use of this function is often an indicator of bad design. Avoid it
|
||||
if you can. (Implementation note: This function is supported because
|
||||
XSLT's XML output method requires it.)"
|
||||
(maybe-emit-start-tag)
|
||||
(sax:unescaped *sink* (rod str)))
|
||||
|
||||
@ -598,9 +598,22 @@
|
||||
;;;; DTD
|
||||
;;;;
|
||||
|
||||
(define-condition xml-parse-error (simple-error) ())
|
||||
(define-condition well-formedness-violation (xml-parse-error) ())
|
||||
(define-condition validity-error (xml-parse-error) ())
|
||||
(define-condition xml-parse-error (simple-error) ()
|
||||
(:documentation
|
||||
"Superclass of all conditions signalled by the CXML parser."))
|
||||
|
||||
(define-condition well-formedness-violation (xml-parse-error) ()
|
||||
(:documentation
|
||||
"This condition is signalled for all well-formedness violations.
|
||||
|
||||
Note for validating mode: Sometimes violations of well-formedness are
|
||||
first detected as validity errors by the parser and signalled as
|
||||
instances of @class{validity-error} rather
|
||||
than well-formedness-violation."))
|
||||
|
||||
(define-condition validity-error (xml-parse-error) ()
|
||||
(:documentation
|
||||
"Reports the violation of a validity constraint."))
|
||||
|
||||
;; We make some effort to signal end of file as a special condition, but we
|
||||
;; don't actually try very hard. Not sure whether we should. Right now I
|
||||
@ -912,6 +925,33 @@
|
||||
(public nil :type (or rod null))
|
||||
(system (error "missing argument") :type (or puri:uri null)))
|
||||
|
||||
(setf (documentation 'extid 'type)
|
||||
"Represents an External ID, consisting of a Public ID and a System ID.
|
||||
|
||||
@see-constructor{make-extiid}
|
||||
@see-slot{exitid-system}
|
||||
@see-slot{exitid-public}")
|
||||
|
||||
(setf (documentation #'make-extid 'function)
|
||||
"@arg[publicid]{string or nil}
|
||||
@arg[systemid]{@class{puri:uri} or nil}
|
||||
@return{an instance of @class{extid}}
|
||||
|
||||
Create an object representing the External ID composed
|
||||
of the specified Public ID and System ID.")
|
||||
|
||||
(setf (documentation #'extid-public 'function)
|
||||
"@arg[extid]{A @class{extid}}
|
||||
@return[publicid]{string or nil}
|
||||
|
||||
Returns the Public ID part of this External ID.")
|
||||
|
||||
(setf (documentation #'extid-system 'function)
|
||||
"@arg[extid]{A @class{extid}}
|
||||
@return[sytemid]{puri:uri or nil}
|
||||
|
||||
Returns the System ID part of this External ID.")
|
||||
|
||||
(defun absolute-extid (source-stream extid)
|
||||
(let ((sysid (extid-system extid))
|
||||
(result (copy-extid extid)))
|
||||
@ -3099,6 +3139,49 @@
|
||||
(input handler &rest args
|
||||
&key validate dtd root entity-resolver disallow-internal-subset
|
||||
recode pathname)
|
||||
"@arg[input]{A string, pathname, octet vector, or stream.}
|
||||
@arg[handler]{A @class{SAX handler}}
|
||||
@arg[validate]{Boolean. Defaults to @code{nil}. If true, parse in
|
||||
validating mode, i.e. assert that the document contains a DOCTYPE
|
||||
declaration and conforms to the DTD declared.}
|
||||
@arg[dtd]{unless @code{nil}, an extid instance specifying the external
|
||||
subset to load. This options overrides the extid specified in the
|
||||
document type declaration, if any. See below for @fun{make-extid}.
|
||||
This option is useful for verification purposes together with the
|
||||
@var{root} and @var{disallow-internal-subset} arguments.}
|
||||
@arg[root]{The expected root element name, or @code{nil} (the default).
|
||||
If specified, this argument overrides the name stated in the input's
|
||||
DOCTYPE (if any).}
|
||||
@arg[entity-resolver]{@code{nil} or a function of two arguments which
|
||||
is invoked for every entity referenced by the document with the
|
||||
entity's Public ID (a rod) and System ID (an URI object) as arguments.
|
||||
The function may either return nil, CXML will then try to resolve the
|
||||
entity as usual. Alternatively it may return a Common Lisp stream
|
||||
specialized on @code{(unsigned-byte 8)} which will be used instead.
|
||||
(It may also signal an error, of course, which can be useful to prohibit
|
||||
parsed XML documents from including arbitrary files readable by
|
||||
the parser.)}
|
||||
@arg[disallow-internal-subset]{Boolean. If true, signal
|
||||
an error if the document contains an internal subset.}
|
||||
@arg[recode]{Boolean. (Ignored on Lisps with Unicode
|
||||
support.) Recode rods to UTF-8 strings. Defaults to true.
|
||||
Make sure to use @fun{utf8-dom:make-dom-builder} if this
|
||||
option is enabled and @fun{rune-dom:make-dom-builder}
|
||||
otherwise.}
|
||||
@return{The value returned by @fun{sax:end-document} on @var{handler}.}
|
||||
|
||||
Parse an XML document from @var{input}, which can be a string, pathname,
|
||||
octet vector, or stream.
|
||||
|
||||
Return values from this function depend on the SAX handler used.
|
||||
This is an old-style convenience wrapper around the new-style interface
|
||||
@fun{parse}.
|
||||
|
||||
Parse an XML document from @var{filename}, and signal SAX events to
|
||||
@var{handler} while doing so.
|
||||
|
||||
All SAX parsing functions share the same keyword arguments. Refer to
|
||||
@fun{parse} for details on keyword arguments."
|
||||
(declare (ignore validate dtd root entity-resolver disallow-internal-subset
|
||||
recode))
|
||||
(let ((args
|
||||
@ -3133,6 +3216,18 @@
|
||||
(wf-error xstream "~A" c)))))
|
||||
|
||||
(defun parse-file (filename handler &rest args)
|
||||
"@arg[filename]{An pathname designator.}
|
||||
@arg[handler]{A @class{SAX handler}}
|
||||
@return{The value returned by @fun{sax:end-document} on @var{handler}.}
|
||||
|
||||
This is an old-style convenience wrapper around the new-style interface
|
||||
@fun{parse}.
|
||||
|
||||
Parse an XML document from @var{filename}, and signal SAX events to
|
||||
@var{handler} while doing so.
|
||||
|
||||
All SAX parsing functions share the same keyword arguments. Refer to
|
||||
@fun{parse} for details on keyword arguments."
|
||||
(with-open-xfile (input filename)
|
||||
(setf (xstream-name input)
|
||||
(make-stream-name
|
||||
@ -3154,7 +3249,46 @@
|
||||
(pathname-to-uri (merge-pathnames (pathname stream)))
|
||||
nil))
|
||||
|
||||
(deftype |SAX HANDLER| ()
|
||||
'sax:abstract-handler
|
||||
"Historically, any object has been usable as a SAX handler with CXML,
|
||||
as long as it implemented all SAX events, i.e. had methods
|
||||
for the generic functions defined in the SAX package.
|
||||
|
||||
While this approach still works, it is now recommended that SAX handlers
|
||||
should be implemented by subclassing @class{abstract-handler} or one
|
||||
of its subclasses. Useful subclasses are @class{content-handler}
|
||||
and @class{default-handler}.
|
||||
|
||||
(In addition, the value @code{nil} is valid SAX handler, which discards
|
||||
all events it receives.)
|
||||
|
||||
As a rule of thumb, write a subclass of @class{default-handler} if
|
||||
you want to handle only a few special SAX events and ignore the rest,
|
||||
because this class has no-op default methods for all events.
|
||||
|
||||
If, however, you want to make certain that your class implements all
|
||||
important SAX events explicitly, a good choice is @class{content-handler},
|
||||
which has no-op default methods only for less important, DTD-related
|
||||
events, and requires subclasses to implement all events related to the
|
||||
content model.
|
||||
|
||||
In some cases, it might be helpful to implement @class{abstract-handler}
|
||||
directly, which has no default event methods at all.")
|
||||
|
||||
(defun parse-stream (stream handler &rest args)
|
||||
"@arg[stream]{An (unsigned-byte 8) stream}
|
||||
@arg[handler]{A @class{SAX handler}}
|
||||
@return{The value returned by @fun{sax:end-document} on @var{handler}.}
|
||||
|
||||
This is an old-style convenience wrapper around the new-style interface
|
||||
@fun{parse}.
|
||||
|
||||
Parse an XML document from @var{stream}, and signal SAX events to
|
||||
@var{handler} while doing so.
|
||||
|
||||
All SAX parsing functions share the same keyword arguments. Refer to
|
||||
@fun{parse} for details on keyword arguments."
|
||||
(let ((xstream
|
||||
(make-xstream
|
||||
stream
|
||||
@ -3167,6 +3301,33 @@
|
||||
|
||||
(defun parse-empty-document
|
||||
(uri qname handler &key public-id system-id entity-resolver (recode t))
|
||||
"@arg[uri]{a string or nil}
|
||||
@arg[qname]{a string or nil}
|
||||
@arg[handler]{a @class{SAX handler}}
|
||||
@arg[public-id]{a string or nil}
|
||||
@arg[system-id]{a @type{puri:uri} or nil}
|
||||
@arg[entity-resolver]{@code{nil} or a function of two arguments which
|
||||
is invoked for every entity referenced by the document with the
|
||||
entity's Public ID (a rod) and System ID (an URI object) as arguments.
|
||||
The function may either return nil, CXML will then try to resolve the
|
||||
entity as usual. Alternatively it may return a Common Lisp stream
|
||||
specialized on @code{(unsigned-byte 8)} which will be used instead.
|
||||
(It may also signal an error, of course, which can be useful to prohibit
|
||||
parsed XML documents from including arbitrary files readable by
|
||||
the parser.)}
|
||||
@arg[recode]{Boolean. (Ignored on Lisps with Unicode
|
||||
support.) Recode rods to UTF-8 strings. Defaults to true.
|
||||
Make sure to use @fun{utf8-dom:make-dom-builder} if this
|
||||
option is enabled and @fun{rune-dom:make-dom-builder}
|
||||
otherwise.}
|
||||
@return{The value returned by @fun{sax:end-document} on @var{handler}.}
|
||||
|
||||
Simulate parsing of a document with a document element @var{qname}
|
||||
having no attributes except for an optional namespace
|
||||
declaration to @var{uri}. If an external ID is specified
|
||||
(@var{system-id}, @var{public-id}), find, parse, and report
|
||||
this DTD as if with @fun{parse-file}, using the specified
|
||||
entity resolver."
|
||||
(check-type uri (or null rod))
|
||||
(check-type qname (or null rod))
|
||||
(check-type public-id (or null rod))
|
||||
@ -3224,10 +3385,24 @@
|
||||
(sax:end-document handler)))
|
||||
|
||||
(defun parse-dtd-file (filename &optional handler)
|
||||
"@arg[filename]{An pathname designator.}
|
||||
@arg[handler]{A @class{SAX handler}}
|
||||
@return{A @class{dtd} instance.}
|
||||
|
||||
Parse @a[http://www.w3.org/TR/2000/REC-xml-20001006#NT-extSubset]{declarations}
|
||||
from @var{filename} and return an object representing the DTD,
|
||||
suitable as an argument to @code{validate} with @fun{parse}."
|
||||
(with-open-file (s filename :element-type '(unsigned-byte 8))
|
||||
(parse-dtd-stream s handler)))
|
||||
|
||||
(defun parse-dtd-stream (stream &optional handler)
|
||||
"@arg[stream]{An (unsigned-byte 8) stream.}
|
||||
@arg[handler]{A @class{SAX handler}}
|
||||
@return{A @class{dtd} instance.}
|
||||
|
||||
Parse @a[http://www.w3.org/TR/2000/REC-xml-20001006#NT-extSubset]{declarations}
|
||||
from @var{stream} and return an object representing the DTD,
|
||||
suitable as an argument to @code{validate} with @fun{parse}."
|
||||
(let ((input (make-xstream stream)))
|
||||
(setf (xstream-name input)
|
||||
(make-stream-name
|
||||
@ -3245,6 +3420,22 @@
|
||||
(dtd *ctx*))))))
|
||||
|
||||
(defun parse-rod (string handler &rest args)
|
||||
"@arg[string]{An string of unicode characters.}
|
||||
@arg[handler]{A @class{SAX handler}}
|
||||
@return{The value returned by @fun{sax:end-document} on @var{handler}.}
|
||||
|
||||
This is an old-style convenience wrapper around the new-style interface
|
||||
@fun{parse}.
|
||||
|
||||
Parse an XML document from @var{string}, and signal SAX events to
|
||||
@var{handler} while doing so.
|
||||
|
||||
Note: This function assumes that @var{string} has already been decoded into
|
||||
Unicode runes and ignores the encoding specified in the XML declaration,
|
||||
if any.
|
||||
|
||||
All SAX parsing functions share the same keyword arguments. Refer to
|
||||
@fun{parse} for details on keyword arguments."
|
||||
(let ((xstream (string->xstream string)))
|
||||
(setf (xstream-name xstream)
|
||||
(make-stream-name
|
||||
@ -3257,6 +3448,18 @@
|
||||
(make-rod-xstream (string-rod string)))
|
||||
|
||||
(defun parse-octets (octets handler &rest args)
|
||||
"@arg[octets]{An (unsigned-byte 8) vector.}
|
||||
@arg[handler]{A @class{SAX handler}}
|
||||
@return{The value returned by @fun{sax:end-document} on @var{handler}.}
|
||||
|
||||
This is an old-style convenience wrapper around the new-style interface
|
||||
@fun{parse}.
|
||||
|
||||
Parse an XML document from @var{octets}, and signal SAX events to
|
||||
@var{handler} while doing so.
|
||||
|
||||
All SAX parsing functions share the same keyword arguments. Refer to
|
||||
@fun{parse} for details on keyword arguments."
|
||||
(apply #'parse-stream (make-octet-input-stream octets) handler args))
|
||||
|
||||
;;;;
|
||||
@ -3705,6 +3908,22 @@
|
||||
(cdatap :initform nil :accessor cdatap)))
|
||||
|
||||
(defun make-validator (dtd root)
|
||||
"@arg[dtd]{An @class{dtd} instance.}
|
||||
@arg[root]{Element name, a string.}
|
||||
@return{A @class{SAX handler}.}
|
||||
|
||||
Create a SAX handler which validates against a DTD instance.
|
||||
The document's root element must be named @code{root}.
|
||||
Used with @fun{dom:map-document}, this validates a document
|
||||
object as if by re-reading it with a validating parser, except
|
||||
that declarations recorded in the document instance are completely
|
||||
ignored.
|
||||
|
||||
Example:
|
||||
|
||||
@pre{(let ((d (parse-file \"~/test.xml\" (cxml-dom:make-dom-builder)))
|
||||
(x (parse-dtd-file \"~/test.dtd\")))
|
||||
(dom:map-document (cxml:make-validator x #\"foo\") d))}"
|
||||
(make-instance 'validator
|
||||
:context (make-context
|
||||
:handler nil
|
||||
|
||||
@ -31,6 +31,12 @@
|
||||
(defvar *xmlns-namespace* #"http://www.w3.org/2000/xmlns/")
|
||||
|
||||
(defun make-namespace-normalizer (chained-handler)
|
||||
"@arg[chained-handler]{A @class{SAX handler}.}
|
||||
@return{A @class{SAX handler}.}
|
||||
|
||||
Return a SAX handler that performs @a[http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/namespaces-algorithms.html#normalizeDocumentAlgo]{DOM
|
||||
3-style namespace normalization} on attribute lists in
|
||||
@fun{sax:start-element} events before passing them on the next handler."
|
||||
(make-instance 'namespace-normalizer
|
||||
:xmlns-stack (list (mapcar (lambda (cons)
|
||||
(make-xmlns-attribute (car cons) (cdr cons)))
|
||||
|
||||
Reference in New Issue
Block a user