.. _xmlio-writing: Writing XML =========== Memory and file writers ----------------------- ``XMLBufferWriter`` retains a document for conversion to a string or immediate reuse by ``XMLReader``. ``XMLFileWriter`` associates the same writer interface with an output filename: .. code-block:: cpp xmlio::XMLBufferWriter memory("settings"); xmlio::XMLFileWriter file("settings.xml", "settings"); xmlio::write(file, "count", 4); file.close(); An explicit ``close`` is recommended for files because it reports output errors. The destructor also closes the file but cannot safely propagate an exception. Creating the document tree -------------------------- A root name may be supplied to the constructor, or the first ``push`` or ``openTag`` may create it. ``push`` makes a new child current and ``pop`` returns to its parent: .. code-block:: cpp xmlio::XMLBufferWriter output("project"); xmlio::push(output, "limits"); xmlio::write(output, "lower", 0.0); xmlio::write(output, "upper", 1.0); xmlio::pop(output); The writer rejects a second document root and attempts to close an element when the stack is empty. ``depth`` exposes the number of open elements when a diagnostic or test needs to verify stack balance. Attributes and empty elements ----------------------------- ``set_attr`` attaches an attribute to the current element. Attribute lists are useful when creating a tag and its attributes together: .. code-block:: cpp xmlio::XMLBufferWriter output; output.openTag( "project", xmlio::AttributeList{ xmlio::Attribute("name", "example"), xmlio::Attribute("version", 2)}); output.emptyTag("marker", {xmlio::Attribute("kind", "checkpoint")}); output.closeTag(); String and arithmetic attributes use the same locale-independent conversion as element values. Namespaces ---------- Namespace declarations are ordinary ``xmlns`` attributes. Qualified elements and attributes require a declared prefix: .. code-block:: cpp xmlio::XMLBufferWriter output; output.openTag( "document", {xmlio::Attribute("xmlns:m", "urn:example:metrics")}); output.openTag("m", "score"); output.write(8.5); output.closeTag(); output.closeTag(); The reader must independently register the prefix before using it in XPath. The prefix chosen for a query need not be the same spelling used in the file; the namespace URI is what identifies the namespace. Text, escaping, and raw XML --------------------------- All normal text and attribute values are escaped by libxml2. A string such as ``A < B & B < C`` therefore remains data and cannot accidentally create tags. ``writeXML`` is different: it parses its argument as a well-formed XML fragment and appends the resulting nodes. Use it only when the caller intentionally has XML rather than plain text. Malformed fragments raise ``WriterError``. Embedding documents ------------------- A reader or memory writer can be embedded by name: .. code-block:: cpp xmlio::XMLBufferWriter result("result"); xmlio::write(result, "input", original_reader); This produces ```` containing the original document root. Streaming a reader with ``operator<<`` inserts its root directly under the current element. Both forms omit the embedded document's XML declaration. Serialization and output ------------------------ ``str`` returns the complete document and accepts a flag controlling the XML declaration. ``printRoot`` returns only the root element. ``print`` writes to a stream, and ``save`` replaces a file with the current document. ``XMLFileWriter`` is DOM buffered. ``flush`` serializes the complete current document and replaces the associated file; it is not an incremental streaming operation. This is appropriate for configuration and ordinary result files. Applications producing very large XML graphs or event streams should evaluate their memory requirements before choosing this writer. Complete composition example ---------------------------- This example preserves an input document inside a result and also extracts deferred operation definitions: .. literalinclude:: examples/composition.cpp :language: cpp :linenos: