There are two common ways to create XML using C#. First, using System.Xml namespace classes and the second, using LINQ to XML. If you're not familiar with LINQ, you may use the System.Xml namespace. In this article, my focus is System.Xml classes. One finished with the System.Xml classes, I will focus on LINQ to XML.
The XML functionality in .NET framework is defined in the System.Xml namespace. You must import the System.Xml in your code before you may use any of the XML classes discussed in this article.
XML Example
Before we create an XML, let's have a quick look at a simple XML file that we will create in this article.
<?xml version="1.0" encoding="utf-8" ?>
<!-- Books.xml stores information about Mahesh Chand and related books -->
<books>
<book ISBN="9831123212" yearpublished="2002">
<title>A Programmer's Guide to ADO.NET using C#</title>
<author>
<first-name>Mahesh</first-name>
<last-name>Chand</last-name>
</author>
<publisher>Apress</publisher>
<price>44.99</price>
</book>
</books>
Listing 1
The XML in Listing 1 starts with the root tag and defines the version and encoding followed by a comment. After that, there is a <books> root element. The <books> element has a child <book> element with ISBN and yearpublished attributes and child tags title, author, publisher, and price.
We have a sample XML. Now let's figure out how to create this with our code.
XmlWriter Class
The XmlWriter class provides functionality to write fast, forward-only, non-cached XML streams. The XmlWriter class also validates and verifies element and attributes names and also ensures that the newly generated XML is well-formed.
The XmlWriter.Create static method is used to create an XmlWriter. The Create method has several overloaded forms and can save the generated XML into various objects.
Before we create a complex XML document, let's create a simple XML. The code listed in Listing 2 creates an XML file called books.xml.
using (XmlWriter writer = XmlWriter.Create("books.xml"))
{
writer.WriteStartElement("book");
writer.WriteElementString("title", "Graphics Programming using GDI+");
writer.WriteElementString("author", "Mahesh Chand");
writer.WriteElementString("publisher", "Addison-Wesley");
writer.WriteElementString("price", "64.95");
writer.WriteEndElement();
writer.Flush();
}
Listing 2
Each XML tag has an opening (start) and closing (end) tag. In Listing 2, we create an XmlWriter object that takes a filename to be created. After that, we call the WriteStartElement method. The WriteStartElement method creates the start tag of an element. After that, we call the WriteElementString method four times with different values that writes an element containing the string value. Then we call the WriteEndElement method that writes the end tag of the start tag. The last call the code is made to the Flush method that flushes whatever is in the buffer.
Listing 2 generates output that looks like Figure 1.
Figure 1
XmlWriter Settings
An XML document has some features such as encoding, indenting, and conformance level and when you create an XML using XmlWriter, you may specify what features are applicable to the document using the XmlWriterSettings class.
Let's take a quick look at the XmlWriterSettings class properties. I know it looks and reads like a lot of documentation but if you want to write good XML, you must understand the XmlWritersSettings properties.
- The CheckCharacters property gets or sets a value indicating whether to do character checking.
- The CloseOutput property gets or sets a value indicating whether the XmlWriter should also close the underlying stream when the Close method is called.
- The ConformanceLevel property gets or sets the level of conformance that the XmlWriter complies with.
- The DoNotEscapeUriAttribute property gets or sets a value that indicates whether the XmlWriter does not escape URI attributes.
- You may overwrite the default encoding of an XML document. The Encoding property gets or sets the type of text encoding to use.
- The Indent property gets or sets a value indicating whether to indent elements.
- The IndentChars property gets or sets the character string to use when indenting. This setting is used when the Indent property is set to true.
- The NamespaceHanding property gets or sets a value that indicates whether the XmlWriter should remove duplicate namespace declarations when writing XML content. The default behavior is for the writer to output all namespace declarations that are present in the writer's namespace resolver.
- The NewLineChars property gets or sets the character string to use for line breaks.
- The NewLineHandling property gets or sets a value indicating whether to normalize line breaks in the output.
- The NewLineOnAttributes property gets or sets a value indicating whether to write attributes on a new line.
- The OmitXmlDeclaration property gets or sets a value indicating whether to omit an XML declaration.
- The OutputMethod property gets the method used to serialize the XmlWriter output.
- The WriteEndDocumentOnClose property gets or sets a value that indicates whether the XmlWriter will add closing tags to all unclosed element tags when the Close method is called.
Alright, now you are familiar with the XmlWriterSettings properties, let's create an XML document to apply these settings. The XmlWriterSettings is passed as a parameter of the XmlWriter.Create method.
The code snippet in Listing 3 creates an XmlWriter with some features by setting the XmlWriter settings. The code creates an XmlWriterSettings and sets its Indent, IndentChars, CloseOutput, and OmitXmlDeclaration properties.
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent =true;
settings.IndentChars = (" ");
settings.CloseOutput = true;
settings.OmitXmlDeclaration =true;
using (XmlWriter writer = XmlWriter.Create("books.xml", settings))
{
writer.WriteStartElement("book");
writer.WriteElementString("title", book.Title);
writer.WriteElementString("author", book.Author.Name);
writer.WriteElementString("publisher", book.Publisher);
writer.WriteElementString("price", book.Price.ToString());
writer.WriteEndElement();
writer.Flush();
}
Listing 3
Creating XmlWriter
The XmlWriter.Create method creates a new XmlWriter instance using several input types such as a Stream, String, StringBuilder, TextWriter, and XmlWriter.
The code snippet in Listing 4 creates an XmlWriter using a MemoryStream with some features by setting the XmlWriter settings.
XmlWriterSettings writerSettings = new XmlWriterSettings();
writerSettings.OmitXmlDeclaration = true;
writerSettings.ConformanceLevel =ConformanceLevel.Fragment;
writerSettings.CloseOutput = false;
MemoryStream localMemoryStream = new MemoryStream();
using (XmlWriter writer = XmlWriter.Create(localMemoryStream, writerSettings))
{
writer.WriteStartElement("book");
writer.WriteElementString("title", "A Programmer's Guide to ADO.NET");
writer.WriteElementString("author", "Mahesh Chand");
writer.WriteElementString("publisher", "APress");
writer.WriteElementString("price", "44.95");
writer.WriteEndElement();
writer.Flush();
}
Listing 4
The following code snippet spits out an XmlWriter contents to the console.
XmlWriter.Create(Console.Out);
Flush and Close Methods
The Flush method flushes whatever is in the buffer to the underlying streams and also flushes the underlying stream. The Close method closes this stream and the underlying. You must directly or indirectly close an XmlWriter. One of the best practices is to use the "using" statement as used in Listing 4 that forces an automatic Close method call on an XmlWriter.
writer.Flush();
writer.Close();
Writing to Console
We can use the Console.Out parameter as a part of the XmlWriter.Create method to spit out XML to the console.
XmlWriter writer = XmlWriter.Create(Console.Out);
The following code snippet creates an XML and spits it out to the console.
using (XmlWriter writer = XmlWriter.Create(Console.Out))
{
writer.WriteStartDocument();
writer.WriteStartElement("Hello XML");
writer.WriteEndElement();
writer.WriteEndDocument();
}
Setting XmlWriter properties
The XmlWriter class contains four properties: Settings, WriterState, XmlLang, and XmlSpace.
The Settings property represents a set of features supported by the XmlWriter.
The WriteState property gets the current state of the XmlWriter class. The values could be Attributes, Start, Element, Content, closed, or Prolog. The return value WriteState.Start means the Write method is not yet called. In other cases, it represents what is being written. For example, the return value WriteState.Attribute means the Attribute value has been written.
The XmlLang property gets the current xml:lang scope.
The XmlSpace property gets the current xml:space scope.
Writing XML Items
The XmlWriter class has many WriteXxx methods to write XML. Most of these methods are self-explanatory. For example, the WriteAttributes method writes out all attributes found at the current position and WriteComment writes out a comment. The WriteComment method writes out a comment and the WriteString method writes text. The code listed in Listing 5 uses the XmlWriter.WriteXXX methods to write DocType, CData, Comment, Element, Attribute, and String element of an XML.
using (XmlWriter writer = XmlWriter.Create(Console.Out))
{
// Write Processing Instruction
String pi = "type=\"text/xsl\" href=\"book.xsl\"";
writer.WriteProcessingInstruction("xml-stylesheet", pi);
// Write DocumentType
writer.WriteDocType("book", null, null, "<!ENTITY h \"hardcover\">");
// Write CDATA
writer.WriteCData("APress Book!");
// Write a Comment
writer.WriteComment("This is a book sample XML");
// Root element - start tag
writer.WriteStartElement("book");
// Write ISBN attribute
writer.WriteAttributeString("ISBN", "9831123212");
// Write year attribute
writer.WriteAttributeString("yearpublished", "2002");
/ Write title
writer.WriteElementString("author", "Mahesh Chand");
/ Write author
writer.WriteElementString("title", "Visual C# Programming");
// Write price
writer.WriteElementString("price", "44.95");
// Root element - end tag
writer.WriteEndElement();
// End Documentd
writer.WriteEndDocument();
// Flush it
writer.Flush();
}
Listing 5
Writing XML Characters
The WriteChars method of the XmlWriter class writes characters to XML. It takes an array of characters and writes one character at a time. The following code snippet takes an array of characters and writes them to an XML file.
using (XmlWriter writer = XmlWriter.Create("M.xml"))
{
writer.WriteStartDocument();
char[] ch = new char[6];
ch[0] ='m';
ch[1] ='a';
ch[2] ='h';
ch[3] ='e';
ch[4] ='s';
ch[5] ='h';
writer.WriteStartElement("WriteChars");
writer.WriteChars(ch, 0, ch.Length);
writer.WriteEndElement();
writer.WriteEndDocument();
}
Summary
The .NET Framework provides a dedicated namespace to work with XML documents called the System.Xml. In this article, we learned how to use this namespace and the classes defined in this namespace to create XML documents. We reviewed the XmlWriter class that is used to write XML. Then we discussed the settings and properties of an XmlWriter and how to create and close XmlWriter. We also discussed how to create an XML and show it to the system console.
More Readings