Well-Formed XML Creation with the XmlTextWriter
The XmlTextWriter, derived from the XmlWriter, writes XML to a file, console, stream, and other output types. When writing XML, the methods do extra work to produce well-formed XML. The following table provides a list of methods that do work for you to ensure that data is well-formed.
Method |
Description of work done |
---|---|
WriteAttributeString |
XmlTextWriter escapes the text content of the attribute depending on what it finds. |
WriteString |
XmlTextWriter escapes special characters, replacing them with & < > and numeric character entities when required. |
WriteBase64 |
XmlTextWriter encodes the base64 bytes, which can then be read using ReadBinary on the XmlReader. |
The following additional tasks are done by the XmlTextWriter to ensure well-formed XML:
Ensures that the XML elements are written out in the correct order. For example, it will not let you write an attribute outside of an element, write a CDATA block inside an attribute, or write multiple root elements. In addition, it ensures that the <?xml declaration comes first and that the <!DOCTYPE node comes before the root element.
Ensures that value and format of the xml:space attribute is correct and makes sure that its value is acceptable according to the World Wide Web Consortium (W3C) Extensible Markup Language (XML) 1.0 (Second Edition) Recommendation. The following example shows the use of a valid value for xml:space in the WriteAttributeString method:
w.WriteAttributeString("xml:space", "", "preserve");
Valid values for the xml:space attribute are default and preserve. If the argument is not one of these values, an ArgumentException is thrown.
Checks when a string is used as a parameter (for example Null==String.Empty and String.Empty) and whether it follows the W3C rules.
The following table shows the additional methods and properties that are defined by the XmlTextWriter that are not inherited or defined in XmlWriter or inherited from Object.
Method or property |
Description |
---|---|
Creates an instance of the XmlTextWriter, which takes a filename, stream, or TextWriter. An overloaded method exists to take an additional parameter that defines the encoding type. |
|
Specifies whether namespaces are supported. When this is set to false, xmlns declarations are not written, and you can specify element names containing any number of colons. |
|
Defines whether indenting is used to format the output. |
|
Defines which character to use for indenting, when doing indented Formatting. |
|
Defines how many IndentChars to write for each level in the hierarchy when doing indented Formatting. |
|
Defines which character to use to quote attribute values. This must be a single quote ' or a double quote ". |
|
Returns the stream that the XmlTextWriter is writing to. Returns null if the XmlTextWriter was constructed with a TextWriter that is not derived from StreamWriter. |
The following example creates XML output using the XmlTextWriter.
Shared Sub WriteQuote(writer As XmlWriter, symbol As String, price As Double, change As Double, volume As Long)
writer.WriteStartElement("Stock")
writer.WriteAttributeString("Symbol", symbol)
writer.WriteElementString("Price", XmlConvert.ToString(price))
writer.WriteElementString("Change", XmlConvert.ToString(change))
writer.WriteElementString("Volume", XmlConvert.ToString(volume))
writer.WriteEndElement()
End Sub 'WriteQuote
Public Shared Sub Main()
Dim writer As New XmlTextWriter(Console.Out)
writer.Formatting = Formatting.Indented
WriteQuote(writer, "MSFT", 74.125, 5.89, 69020000)
writer.Close()
End Sub 'Main
static void WriteQuote(XmlWriter writer, string symbol,
double price, double change, long volume)
{
writer.WriteStartElement("Stock");
writer.WriteAttributeString("Symbol", symbol);
writer.WriteElementString("Price", XmlConvert.ToString(price));
writer.WriteElementString("Change", XmlConvert.ToString(change));
writer.WriteElementString("Volume", XmlConvert.ToString(volume));
writer.WriteEndElement();
}
public static void Main(){
XmlTextWriter writer = new XmlTextWriter(Console.Out);
writer.Formatting = Formatting.Indented;
WriteQuote(writer, "MSFT", 74.125, 5.89, 69020000);
writer.Close();
}
Output
<Stock Symbol="MSFT">
<Price>74.125</Price>
<Change>5.89</Change>
<Volume>69020000</Volume>
</Stock>
The input to the WriteQuote method is the stock symbol, which comes in as a string. The price and change are declared as double, and the volume is long. To convert these variables to strings, the XmlConvert class is used. It has methods that convert all strong-data types to strings. In addition, the XmlConvert class has methods that do the opposite conversion by converting strings to Microsoft .NET Framework data types. For more information, see Character Encoding of XML Names and Conversion of XML Data Types.
For sample code that demonstrates writing XML to a file, see XmlTextWriter.WriteProcessingInstruction. For sample code that demonstrates writing XML to the console, see XmlTextWriter.WriteString.
The following code shows how to write an element that produces <price>19.95</price>:
'Write the price.
writer.WriteElementString("price", "19.95")
//Write the price.
writer.WriteElementString("price", "19.95");
The following code shows how to write an attribute that produces <element name="purchaseOrder"/>:
writer.WriteStartElement("element")
writer.WriteAttributeString("name", "purchaseOrder")
writer.WriteEndElement()
writer.WriteStartElement("element");
writer.WriteAttributeString("name", "purchaseOrder");
writer.WriteEndElement();
WriteAttributeString Method Writes Attributes and Namespace Declarations
The WriteAttributeString method has two different tasks. One task is to write out attributes and associate them with a user-defined namespace prefix. The second task is to generate namespace declarations. If writing attributes and the localname parameter is xmlns, then this method is considered to be creating a namespace declaration.
In the following code example, the WriteAttributeString method is used to write attributes inside an element.
'Write the genre attribute.
writer.WriteAttributeString("genre", "novel")
'Write the ISBN attribute.
writer.WriteAttributeString("ISBN", "1-8630-014")
//Write the genre attribute.
writer.WriteAttributeString("genre", "novel");
//Write the ISBN attribute.
writer.WriteAttributeString("ISBN", "1-8630-014");
The WriteAttributeString also escapes the text content of the attribute, depending on what it finds. If double quotes are used, the XmlTextWriter escapes them in the text content of the attribute value with ". If single quotes are used, it escapes the text content of the attribute value with '.
To generate namespace declarations, there is an overloaded WriteAttributeString method that allows the application to define a namespace declaration. The following code example creates two default namespaces. The first declaration binds all elements with no prefix to the first namespace declaration, while any element declared with a "po" prefix is bound to the second namespace declaration.
' Write the default namespace, identified as xmlns with no prefix
writer.WriteAttributeString("xmlns", Nothing, "http://www.w3.org/2000/10/XMLSchema")
' Write a namespace for the purchase order with a prefix of "po"
writer.WriteAttributeString("xmlns", "po", Nothing, "https://contoso.com/po")
// Write the default namespace, identified as xmlns with no prefix
writer.WriteAttributeString("xmlns", null, "http://www.w3.org/2000/10/XMLSchema");
// Write a namespace for the purchase order with a prefix of "po"
writer.WriteAttributeString("xmlns", "po", null, "https://contoso.com/po");
Close Method
The Close method checks that the XML document is valid when the stream is closed. This prevents invalid XML documents from being created and ensures that the XML is well-formed. In addition to closing the stream, the Close method also calls all necessary WriteEnd<xxx> methods to close the document.
Method Pairs
Methods in the XmlWriter also come in pairs; the WriteStartDocument and WriteEndDocument, WriteStartElement and WriteEndElement, and WriteStartAttribute and WriteEndAttribute method pairs. For example, using these methods you can create nested elements or attributes. It is with these method pairs that an XML document is built and allows the creation of complex elements or attributes.
WriteStartDocument and WriteEndDocument Methods
The WriteStartDocument starts a new document and writes the XML declaration with version attribute set to "1.0", and the WriteEndDocument closes that document. Between calling the next WriteStartDocument to start writing the next document, the formatting, indentation, and other properties can be modified. The WriteStartDocument method programmatically recognizes an XML document is being written and applies root-level rules. If this method is not used, an XML fragment is created and it verifies whether it is well-formed. Root level rules are not applied. The following code example shows the start and end in a document.
' Write the XML declaration.
writer.WriteStartDocument()
. . .
' Close the document.
writer.WriteEndDocument()
// Write the XML declaration.
writer.WriteStartDocument();
. . .
// Close the document.
writer.WriteEndDocument();
WriteStartElement and WriteEndElement Methods
The WriteStartElement and WriteEndElement pair delimits one or more elements. In all the overridden WriteStartElement methods, a local name for the start tag is a required parameter. The following code uses the WriteStartElement and WriteEndElement method pair.
' Write the title.
writer.WriteStartElement("title")
writer.WriteString("The Handmaid's Tale")
writer.WriteEndElement()
// Write the title.
writer.WriteStartElement("title");
writer.WriteString("The Handmaid's Tale");
writer.WriteEndElement();
Output
<title>The Handmaid's Tale</title>
The WriteStartElement provides an overridden method signature that enables the code to specify namespace prefixes for its elements. For more information, see Element Namespace Prefixes in the XmlTextWriter.
WriteStartAttribute and WriteEndAttribute Methods
The WriteStartAttribute and WriteEndAttribute are similar to other start and end methods, except these methods start and end attributes. The WriteStartAttribute writes the start of the attribute, a WriteString method is used to write the attribute value, and the WriteEndAttribute ends the attribute tag. The following code example shows the WriteStartAttribute and WriteEndAttribute method pair.
writer.WriteStartAttribute(prefix, "ISBN", "urn:samples")
writer.WriteString("1-861003-78")
writer.WriteEndAttribute()
writer.WriteStartAttribute(prefix, "ISBN", "urn:samples");
writer.WriteString("1-861003-78");
writer.WriteEndAttribute();
Output
<book bk:ISBN="1-861003-78">
The WriteStartAttribute has an overloaded method that enables an application to specify a namespace prefix so that it can associate the namespace prefix with the attributes that it writes. For more information, see Attribute Namespace Prefixes in the XmlTextWriter.
See Also
Concepts
XML Output Formatting with XmlTextWriter
Namespace Features within the XmlTextWriter