.NET provides a useful feature to simplify the creation of XML without using DOM. The abstract System.Xml.XmlWriter class defines the functionality for a fast, noncached mechanism to generate streams or files containing well-formed XML; XmlTextWriter provides a concrete implementation of this functionality.
Although the XmlTextWriter class is primarily an implementation of XmlWriter, it also contains a number of noninherited members. We highlight these members as they are discussed.
XmlTextWriter provides three constructors; the constructor arguments identify the destination where the XmlTextWriter should write to as well as the encoding to use. These constructors are summarized in Table 11-14.
Table 11-14. The XmlTextWriter Constructors
Constructor | Comments |
---|---|
XmlTextWriter(TextWriter) | Creates an XmlTextWriter that writes to the specified System.IO.TextWriter. Uses the encoding configured on the TextWriter instance. |
XmlTextWriter(Stream, Encoding) | Creates an XmlTextWriter that writes to a System.IO.Stream using the specified System.Text.Encoding. If the Encoding argument is null, the default is UTF-8 encoding. |
XmlTextWriter(string, Encoding) | Creates an XmlTextWriter that writes to the file with the name specified in the string argument using the System.Text.Encoding provided. If the Encoding argument is null, the default is UTF-8 encoding. The XmlTextWriter overwrites the file if it exists. |
The XmlTextWriter.BaseStream property returns the underlying Stream used for output. If the XmlTextWriter was created from a TextWriter that doesn’t derive from System.IO.StreamWriter, null is returned.
The WriteState property returns a value from the System.Xml.WriteState enumeration indicating the current state of the writer; valid values are summarized in Table 11-15.
Table 11-15. The System.Xml.WriteState Enumeration
Value | Comment |
---|---|
Attribute | The XmlTextWriter is currently writing an attribute value. |
Closed | The XmlTextWriter.Close method has been called. |
Content | The XmlTextWriter is currently writing element content. |
Element | The XmlTextWriter is currently writing an element tag. |
The XmlTextWriter is currently writing the XML prolog. | |
Start | The XmlTextWriter is in the initial state; no write methods have been called. |
The XmlTextWriter provides methods for writing all types of XML nodes. Use of the XmlTextWriter methods is straightforward, and complete coverage is included in the .NET documentation. The following example demonstrates the use of many of these methods:
using System; using System.Xml; public class xmlwritetest { public static void Main () { XmlTextWriter wtr = new XmlTextWriter("output.xml", null); // Write the XML declaration wtr.WriteStartDocument(); // Write white space to start a new line followed by a comment wtr.WriteWhitespace(" "); wtr.WriteComment("An XmlTextWriter example."); // Write the <root> start tag and an attribute wtr.WriteStartElement("root"); wtr.WriteAttributeString("anAttribute", "an attribute value"); // Write a complete element in a single call. Special // symbols are automatically replaced with entity references wtr.WriteElementString("node1", "The contents of <node1>"); // Write <node2> start tag, CData section and </node2> end tag wtr.WriteStartElement("node2"); wtr.WriteCData("This CData is contained in the <node2> node"); wtr.WriteEndElement(); // Write the <node3> start tag with two attributes wtr.WriteStartElement("node3"); wtr.WriteStartAttribute("", "Attribute1", ""); wtr.WriteString("Attribute value 1"); wtr.WriteEndAttribute(); wtr.WriteAttributeString("Attribute2", "Attribute value 2"); // Write an element with some text content wtr.WriteStartElement("node4"); wtr.WriteString("The content of node4"); wtr.WriteEndElement(); // Write raw XML wtr.WriteRaw("<node5>Manually formatted XML</node5>"); // Write a complete element in a single call wtr.WriteElementString("node6", "The contents of <node6>"); // WriteEndDocument automatically closes any open elements // In this case <root> and <node3> are closed. wtr.WriteEndDocument(); wtr.Close(); } }
The output from the preceding code is as follows:
<?xml version="1.0"?> <!An XmlTextWriter example.><root anAttribute="an attribute value"><no de1>The contents of <node1><node1><node2><![CDATA[This CData is contained in the <node2> node]]><node2><node3 Attribute1="Attribute va lue 1" Attribute2="Attribute value 2"><node4>The content of node4</ node4><node5>Manually formatted XML<node5><node6>The contents of <n ode6></node6></node3></root>
As can be seen from the preceding example, the XmlTextReader output is unformatted and difficult to read. However, XmlTextWriter provides four properties that enable the programmer to control the indentation of XML output as well as the quotation mark used for attribute values. Indentation affects only the following node types: DocumentType, Element, Comment, ProcessingInstruction, and CDATASection.
XmlTextWriter doesn’t inherit these properties from XmlWriter; we summarize them in Table 11-16.
Table 11-16. The XmlTextWriter Properties
Comments | |
---|---|
Formatting | Controls how the XML output by XmlTextWriter is formatted by using a value from the System.Xml.Formatting enumeration. Valid values are |
| |
Indentation | When Indented Formatting is used, Indentation specifies the number of IndentChar characters to use as indentation for each level of the XML hierarchy (specified as an int). |
IndentChar | The char to use for indenting; default to a space. |
QuoteChar | The quotation mark to use with attribute values; must be either a single quotation mark or a double quotation mark. |
In the preceding example, the output was one long string. If instead we configure the formatting of the XmlTextWriter with the following statements:
XmlTextWriter wtr = new XmlTextWriter("output.xml", null); wtr.Formatting = Formatting.Indented; wtr.Indentation = 2; wtr.QuoteChar = 'u0027';
the output will look as follows:
<?xml version='1.0'?> <!--An XmlTextWriter example.--> <root anAttribute='an attribute value'> <node1>The contents of <node1></node1> <node2><![CDATA[This CData is contained in the <node2> node]]></node2> <node3 Attribute1='Attribute value 1' Attribute2='Attribute value 2'> <node4>The content of node4</node4><node5>Manually formatted XML</ node5><node6>The contents of <node6></node6></node3> </root>
The XmlTextWriter.Namespaces property controls whether the XmlTextWriter supports XML namespaces; by default, namespace support is enabled. If namespace support is enabled, the XmlTextWriter maintains a namespace stack that tracks the namespaces defined by elements. The LookupPrefix method is used to find the namespace prefix based on a Uniform Resource Name (URN).
The XmlTextWriter methods demonstrated in the preceding example that write elements and attributes offer overloaded versions accepting strings to define and use namespaces and prefixes.
The Close method automatically calls any WriteEndXXX methods necessary to close document nodes created with a matching WriteStartXXX method, where XXX identifies a node type. The Close method then closes the XmlTextWriter and the underlying output stream. If Close isn’t called, output buffers won’t be flushed correctly. An InvalidOperationException is thrown if further write methods are invoked after the Close method is called.