XML documents are first and foremost text files, so writing them doesn't need to be complicated. Any set of functions that lets you create and edit a text file is fine for persisting XML data. However, XML documents aren't ordinary text files because you need to ensure that XML files are well formed and that they follow the correct schema. In particular, when you use a standard (not made-to-measure) API, errors can easily slip into the code, such as missing closing tags, mismatched tag names, and unquoted attribute values.
You can programmatically write an XML file by using the methods of the XML Document Object Model (DOM). If you choose this approach, however, you're required to create in memory the entire tree of nodes and attributes and then persist the tree in a single shot to the disk. You use the XML DOM's methods to build the tree, which guarantees that the document is well formed but consumes excessive processing resources. This approach treats a disk-based XML document as it would a file in which a particular instance of an XML DOM object is persisted. The XML DOM doesn't accommodate any form of progressive dumping. In other words, the XML DOM is good for in-memory processing and searching but not for XML input and output.
In previous issues, I reviewed the XML reader classes and how to use them to read XML content from disk files. Although XML readers are the preferred way to read XML data in the .NET architecture, the XML writer classes are the most natural way to create XML documents directly to disk files.
The base and abstract .NET class that contains the main functionality of XML writers is XmlWriter. But XmlTextWriter is likely the base class that you'll use in your XML applications. This class offers several functions. It lets you set the namespace and the tag prefix, choose the character set, and define whether an indentation is necessary, which character to use, and how large you want the character to be.
XmlTextReader uses a stream-based interface and offers specialized methods to help you write specific XML nodes and typed attributes. You create an instance of the XmlTextWriter class with the following syntax:
XmlTextWriter xtw = new XmlTextWriter(fileName, null);
The first argument is the fully qualified name of the XML file you want to create. The second argument identifies the character set you choose. If you don't specify the character set, the class defaults to the UTF-8 character set.
After you have a valid instance of the XmlTextWriter class, you can adapt a few of its settings to your needs. In particular, you can require that a newline character be appended at the end of each node. Note that the definition of a node includes the open tag, any attribute, the text, and the closing tag. You use the following code to set the automatic newline character:
xtw.Formatting = Formatting.Indented;
If you omit this, the file will be difficult to read because its contents will be presented as one long line of text. In addition to setting the formatting style, you can also require automatic indentation as follows:
xtw.Indentation = 4;
The Indentation property lets you set the indentation to a specific number of characters. By default, the indentation character is a blank space.
After you set up the stream for output, you can begin to write text. You usually begin with the standard XML signature
The WriteStartDocument method writes this line plus any information related to the particular character encoding you want.
WriteComment is the method you use to add descriptive text. For example,
xtr.WriteComment("This is my file");
originates the following output:
<!-- This is my file -->
The methods WriteStartElement and WriteEndElement open and close the specified tag. You use only WriteStartElement to specify the name of the tag. Each call to this method causes the class to internally store the pending tags; the next call to WriteEndElement closes the outermost tag.
xtw.WriteStartElement("MyTag"); xtw.WriteString("Contents of the tag"); xtw.WriteEndElement();
You use the WriteString method when you want to write text between the tags. The code above produces the following output:
<MyTag>Contents of the tag</MyTag>
Finally, you can use the following syntax to give attributes to any tag:
You call WriteAttributeString in between the calls to WriteStartElement and WriteEndElement. When you're done with the document, you close it by using
You close the stream by using
XML writers and XML DOMs are radically different objects. Both let you write XML code without concern for whether the code is well formed. But XML writers have a much smaller footprint and are ideal for large files in particular.