Overview
Writing XML: a node or a document, to a port or to a string.
(import (text xml) (text xml write))
(node->xml-string (xml-element (xml-name "p") Nil (list (xml-text "hi"))))
;; (Ok "<p>hi</p>")
(document->xml-string doc #:indent? #t
#:prefixes (list (Tuple "atom" "http://www.w3.org/2005/Atom")))
All four functions take #:indent? and #:prefixes; the
document ones also #:declaration?.
Errors. XmlWriter does all the escaping. Content it
cannot write is an XmlWriteError, not an exception: a character
XML does not allow, U+0000 say, and three it would otherwise change or
drop without a word: a comment containing -- or ending in
-, a processing instruction named xml or with a target
that is not a name, and processing instruction data containing
?>. Whatever was written to a port before the error stays
written, and nothing says how far it got. An exception from the port
itself, an IOException, passes through.
Prefixes. A name has none, so the writer chooses:
- an element uses a prefix already in scope for its namespace, then
a hinted one, then a default namespace declaration,
xmlns="..."; an element in no namespace inside a default namespace getsxmlns="" - an attribute in a namespace always needs a prefix, since the
default namespace does not apply to attributes: one in scope,
then a hinted one, then
ns1,ns2and so on xml:langandxml:spaceusexml, which is never declared
#:prefixes is the hints, as
(list (Tuple "atom" "http://www.w3.org/2005/Atom")). A hinted
prefix is declared once, on the root, for the namespaces the tree uses.
A hint that could not be a prefix (not a name, or xml or
xmlns), or that names no namespace, the xml namespace or
the xmlns one, raises an ArgumentException. A prefix given
twice: the first one is used, and the namespace of the second gets a
generated prefix where the two meet.
Indentation. #:indent? #t puts an element’s children on
lines of their own, two spaces a level, but never where the whitespace
would be content: not inside an element that has text among its
children, not anywhere below one, and not inside
xml:space="preserve". XmlWriter’s own indentation is not
used: it decides only when it meets the text, and by then has indented
the elements before it.
The doctype is the one piece of markup written by hand,
because XmlWriter.WriteDocType wants a C# null for an id that is
not there and there is no null to give it. Its parts are checked
instead of escaped: the name has to be an XML name, a public id needs a
system id with it, and a system id cannot hold both kinds of quote.
Its internal subset is not kept by the reader, so it is not written
back.
See also: node->xml-string, document->xml-string, XmlWriteError
Reference
Types
XmlWriteError
record
Content the writer cannot write, and why.
message- What is wrong.
->str answers the message.
See also: node->xml, document->xml
Functions
node->xml
function
(: node->xml (-> Node TextOutputPort (#:indent? bool) (#:prefixes (List (Tuple string string))) (Result XmlWriteError Unit)))
(node->xml node port #:indent? #f #:prefixes Nil)
Writes a node as XML to a port.
node- The node: an element, a text, a comment or a processing instruction.
port- Where to write it. It is left open.
#:indent?- Whether to put an element's children on lines of their own.
#:prefixes- Prefixes to use, as (Tuple prefix uri).
- returns
- Ok, or the XmlWriteError for what could not be written. What was written before it stays written.
- raises
ArgumentException - When a hint in #:prefixes could not be a prefix, or names no namespace, the xml one or the xmlns one.
See also: node->xml-string, document->xml
node->xml-string
function
(: node->xml-string (-> Node (#:indent? bool) (#:prefixes (List (Tuple string string))) (Result XmlWriteError string)))
(node->xml-string node #:indent? #f #:prefixes Nil)
A node as a string of XML.
node- The node.
#:indent?- Whether to put an element's children on lines of their own.
#:prefixes- Prefixes to use, as (Tuple prefix uri).
- returns
- The XML, or the XmlWriteError for what could not be written.
- raises
ArgumentException - When a hint in #:prefixes could not be a prefix, or names no namespace, the xml one or the xmlns one.
(node->xml-string (xml-element (xml-name "p")
(list (Tuple (xml-name "class") "note"))
(list (xml-text "hi"))))
;; (Ok "<p class=\"note\">hi</p>")
See also: node->xml, document->xml-string
document->xml
function
(: document->xml (-> Document TextOutputPort (#:indent? bool) (#:prefixes (List (Tuple string string))) (#:declaration? bool) (Result XmlWriteError Unit)))
(document->xml doc port #:indent? #f #:prefixes Nil #:declaration? #t)
Writes a document as XML to a port.
doc- The document.
port- Where to write it. It is left open.
#:indent?- Whether to put an element's children, and the nodes around the root, on lines of their own.
#:prefixes- Prefixes to use, as (Tuple prefix uri).
#:declaration?- Whether to begin with the XML declaration.
- returns
- Ok, or the XmlWriteError for what could not be written. What was written before it stays written.
- raises
ArgumentException - When a hint in #:prefixes could not be a prefix, or names no namespace, the xml one or the xmlns one.
The declaration is <?xml version="1.0"?>, with no encoding,
since which one the text ends up in is the port’s business.
See also: document->xml-string, node->xml
document->xml-string
function
(: document->xml-string (-> Document (#:indent? bool) (#:prefixes (List (Tuple string string))) (#:declaration? bool) (Result XmlWriteError string)))
(document->xml-string doc #:indent? #f #:prefixes Nil #:declaration? #t)
A document as a string of XML.
doc- The document.
#:indent?- Whether to put an element's children, and the nodes around the root, on lines of their own.
#:prefixes- Prefixes to use, as (Tuple prefix uri).
#:declaration?- Whether to begin with the XML declaration, <?xml version="1.0"?>.
- returns
- The XML, or the XmlWriteError for what could not be written.
- raises
ArgumentException - When a hint in #:prefixes could not be a prefix, or names no namespace, the xml one or the xmlns one.
See also: document->xml, node->xml-string