XmlWriter is an abstract base class that defines an interface but for writing XML. It is a forward-only, read-only non-cached way of generating XML streams (i.e., document). The design of XmlWriter is the same as XmlReader. XmlWriter currently has only one implementation, XmlTextWriter. However, as of .NET Framework 2.0, you construct an XmlWriter using XmlWriter.Create method with an optional settings object
static public void BasicXmlWriter() { var settings = new XmlWriterSettings(); settings.Indent = true; //settings.OmitXmlDeclaration = true // Ommits <?xml ... > prolog //settings.ConformanceLevel = ConformanceLevel.Fragment; // Allows writing multiuple roots StringBuilder sbXml = new StringBuilder(); using (XmlWriter writer = XmlWriter.Create(sbXml, settings)) { // Start element writer.WriteStartElement("cusotmer"); // Child elements writer.WriteElementString("FirstName", "A"); writer.WriteElementString("LastName", "B"); // Note the XML different between the following // Non-XML compliant and vulnerable to incorrect parsing writer.WriteElementString("birthdate", DateTime.Now.ToString()); // WriteValue internally calls XmlConvert to perofm XML-compliant string conversion writer.WriteStartElement("birthdate1"); writer.WriteValue(DateTime.Now); writer.WriteEndElement(); // You can write attributes immediately after a start element writer.WriteStartElement("Bithplace"); writer.WriteAttributeString("City", "MyCity"); writer.WriteEndElement(); writer.WriteEndElement(); } }
<?xml version="1.0" encoding="utf-16"?> <cusotmer> <FirstName>A</FirstName> <LastName>B</LastName> <birthdate>08/06/2014 14:44:27</birthdate> <birthdate1>2014-06-08T14:44:27.6945971+01:00</birthdate1> <Bithplace City="MyCity" /> </cusotmer>
Other node types can be written using the following methods:
WriteCData
WriteComment
WriteDocType
WriteEntityRef
WriteProcessingInstruction
WriteRaw
WriteWhitespace
etc.
For namespaces and prefixes, the overloads for WriteX methods allow you to associate an element or attribute with a namespace. For example:
static public void BasicXmlWriterWithNamespaces() { var settings = new XmlWriterSettings(); settings.Indent = true; //settings.OmitXmlDeclaration = true // Ommits <?xml ... > prolog //settings.ConformanceLevel = ConformanceLevel.Fragment; // Allows writing multiuple roots StringBuilder sbXml = new StringBuilder(); using (XmlWriter writer = XmlWriter.Create(sbXml, settings)) { // Start element writer.WriteStartElement("ns", "cusotmer", "www.diranieh.com"); // Child elements writer.WriteElementString("FirstName", "A"); writer.WriteElementString("LastName", "B"); writer.WriteEndElement(); } }
<?xml version="1.0" encoding="utf-16"?> <ns:cusotmer xmlns:ns="www.diranieh.com"> <FirstName>A</FirstName> <LastName>B</LastName> </ns:cusotmer>
XmlTextWriter writes to a file, console, stream, and other output types. Some XmlTextWriter methods actually do extra work to ensure that XML is well-formed. For example. XmlTextWriter.Close checks to see that the XML is well-formed and and if not, throws an OperationInvalidException. Another example is XmlTextWriter.WriteAttributeString which escapes the text content of the attribute depending on what it finds. XmlTextWriter performs the following additional tasks:
Some methods in XmlTextWriter come in pairs:
Examples are shown below:
// Write the XML declaration
writer.WriteStartDocument
// Methods to write the body of the XML come here
...
// Finish the document
writer.WriteEndDocument
writer.WriteStartElement("Book");
writer.WriteString("Advanced .NET" );
writer.WriteEndElement()
writer.WriteStartAttribute( "ISBN", "urn:samples")
writer.WriteString("12345-6789" );
writer.WriteEndAttribute(
Several properties of XmlTextWriter work together to control the document format. These properties are:
The first three properties work together while the last one can be considered separately. Of the first three, the main property is Formatting which can be either None or Indented:
Only the following nodes are affected by the Indentation property (all other node types are not affected):
Finally, the last property QuoteChar determines what character to use to quote attribute values. Valid values are single-quote and double-quote. The following example and its output illustrates:
void f()
{
// Create an XML writer
System.IO.StringWriter sw = new System.IO.StringWriter();
XmlTextWriter writer = new XmlTextWriter( sw );
// Use formatting
writer.Formatting = Formatting.Indented;
writer.Indentation = 5;
writer.IndentChar = '_';
// Write XML
writer.WriteStartDocument(false);
writer.WriteStartElement( "Book" );
writer.WriteElementString( "Author", "Yazan" );
writer.WriteElementString( "Title", ".NET" );
writer.WriteEndElement();
writer.WriteEndDocument();
// Display resuls and cleanup
Trace.WriteLine( sw.GetStringBuilder().ToString() );
writer.Close();
}
<?xml version="1.0" encoding="utf-16" standalone="no"?>
<Book>
_____<Author>Yazan</Author>
_____<Title>.NET</Title>
</Book>
Recall that namespaces are used to qualify XML element and attribute names to uniquely identify them from any other XML document. The general technique for using namespaces in XML is to associate a namespace (which is just a name) with a URI, and then prefix elements and attribute with the namespace or its alias
XmlTextWriter supports namespaces as follows:
XmlTextWriter internally maintains a list of all namespaces and tracks the namespace that has been used by an element.
The following example shows the basic namespace support using one of the XmlStartElement overloads. Note how the output automatically contains xmlns attribute.
// Create and initialize and XML
writer
System.IO.StringWriter sw = new System.IO.StringWriter();
XmlTextWriter xw = new XmlTextWriter( sw );
xw.Formatting = Formatting.Indented;
// Write XML
xw.WriteStartElement("Book", "urn:www.diranieh.com");
xw.WriteStartElement("Book" );
xw.WriteString( ".NET Programming" );
xw.WriteEndElement();
xw.WriteEndElement();
// Display results and cleanup
Trace.WriteLine( sw.GetStringBuilder().ToString() );
xw.Close();
<Book xmlns="urn:www.diranieh.com">
<Book>.NET Programming</Book>
</Book>
Same as above exactly except that the Book nested element uses the same namespace used by its parent. Note how the Book element does not repeat the namespace declaration:
xw1.WriteStartElement("Book", "urn:www.diranieh.com");
xw1.WriteStartElement("Book", "urn:www.diranieh.com");
xw1.WriteString( ".NET Programming" );
xw1.WriteEndElement();
xw1.WriteEndElement();
<Book xmlns="urn:www.diranieh.com">
<Book>.NET Programming</Book>
</Book>
The following example illustrates manual namespace declaration:
// Create a writer
System.IO.StringWriter sw2 = new System.IO.StringWriter();
XmlTextWriter xw2 = new XmlTextWriter( sw2 );
xw2.Formatting = Formatting.Indented;
// Write XML. Note use of namespace and namespace alias
string strNamespace = "www.diranieh.com";
xw2.WriteStartElement("Books");
xw2.WriteAttributeString("xmlns", "NS", null,
strNamespace); // xmlns:NS="www.diranieh.com"
//
xw2.WriteStartElement("Book", strNamespace );
xw2.WriteString( ".NET Programming" );
xw2.WriteEndElement();
//
xw2.WriteStartElement("Book", strNamespace );
xw2.WriteString( "Advanced.NET Programming" );
xw2.WriteEndElement();
//
xw2.WriteEndElement();
// Display results and cleanup
Trace.WriteLine( sw2.GetStringBuilder().ToString() );
xw2.Close();
<Books xmlns:NS="www.diranieh.com">
<NS:Book>.NET Programming</NS:Book>
<NS:Book>Advanced.NET Programming</NS:Book>
</Books>
The following example illustrates how to manually override a namespace declaration:
xw.WriteStartElement( "x", "Book",
"www.diranieh.com");
xw.WriteAttributeString( "xmlns", "x", null, "SomeURI"
);
<x:Book xmlns:x="SomeURI" />
XmlWriter.WriteRaw allows you to write raw markup manually while preserving special characters. This is contrast to WriteString method which escapes some strings to their equivalent entity reference. The guiding principle on when to use WriteRaw or WriteString is that WriteRaw writes exactly what it is given, while WriteString is used when you need to walk through every character looking for entity characters. The following example outputs should illustrate:
// WriteString
xw.WriteStartElement("MyItem");
xw.WriteString( "<=" );
// <=
xw.WriteEndElement();
<!-- Output -->
<MyItem><=</MyItem>
// WriteRaw
xw.WriteStartElement("MyItem" );
xw.WriteRaw( "<=" );
// <=
xw.WriteEndElement();
<!-- Output -->
<MyItem><=</MyItem>