XmlWriter
This class
writes XML data from objects in memory. XML files are excellent for interoperability with other systems and Internet sites.
We use XmlWriter
in a C# program, reviewing each step required. The XmlWriter
can give the best performance, but it is not the simplest way to write XML data.
We see an Employee class
, which contains 4 fields, 4 public getters, and a constructor. All the fields are private, not public.
class
is properly encapsulated and has exclusive control over its internal fields.class
is used, and employee items are assigned to the array slots.XmlWriter
, you must assign a variable to the result of the XmlWriter.Create
method.XmlWriter.Create
method is told to create a new file called employees.xml
. This is where we will store the array data.using System.Xml; class Program { class Employee { int _id; string _firstName; string _lastName; int _salary; public Employee(int id, string firstName, string lastName, int salary) { this._id = id; this._firstName = firstName; this._lastName = lastName; this._salary = salary; } public int Id { get { return _id; } } public string FirstName { get { return _firstName; } } public string LastName { get { return _lastName; } } public int Salary { get { return _salary; } } } static void Main() { Employee[] employees = new Employee[4]; employees[0] = new Employee(1, "David", "Smith", 10000); employees[1] = new Employee(3, "Mark", "Drinkwater", 30000); employees[2] = new Employee(4, "Norah", "Miller", 20000); employees[3] = new Employee(12, "Cecil", "Walker", 120000); using (XmlWriter writer = XmlWriter.Create("employees.xml")) { writer.WriteStartDocument(); writer.WriteStartElement("Employees"); foreach (Employee employee in employees) { writer.WriteStartElement("Employee"); writer.WriteElementString("ID", employee.Id.ToString()); writer.WriteElementString("FirstName", employee.FirstName); writer.WriteElementString("LastName", employee.LastName); writer.WriteElementString("Salary", employee.Salary.ToString()); writer.WriteEndElement(); } writer.WriteEndElement(); writer.WriteEndDocument(); } } }
Next, we need to add a root element to the XML. It is important to add a root element with XmlWriter
that contains all the other elements.
using (XmlWriter writer = XmlWriter.Create("employees.xml")) { writer.WriteStartDocument(); writer.WriteStartElement("Employees"); // <-- Important root element writer.WriteEndElement(); // <-- Closes it writer.WriteEndDocument(); }
Next, we can loop through the elements in our Employee array. The array we use here is shown in full in the first block of code above.
WriteStartElement
method begins a new block, which is empty—it contains no data.using (XmlWriter writer = XmlWriter.Create("employees.xml")) { writer.WriteStartDocument(); writer.WriteStartElement("Employees"); foreach (Employee employee in employees) // <-- This is new { writer.WriteStartElement("Employee"); // <-- Write employee element writer.WriteEndElement(); } writer.WriteEndElement(); writer.WriteEndDocument(); }
We take the values from each Employee and access the property getters. The 4 fields from the Employee object are inserted into special tags in the XML.
using (XmlWriter writer = XmlWriter.Create("employees.xml")) { writer.WriteStartDocument(); writer.WriteStartElement("Employees"); foreach (Employee employee in employees) { writer.WriteStartElement("Employee"); writer.WriteElementString("ID", employee.Id.ToString()); // <-- These are new writer.WriteElementString("FirstName", employee.FirstName); writer.WriteElementString("LastName", employee.LastName); writer.WriteElementString("Salary", employee.Salary.ToString()); writer.WriteEndElement(); } writer.WriteEndElement(); writer.WriteEndDocument(); }
I have often encountered this InvalidOperationException
. The problem here is that you always have to put the root element into your document.
Token StartElement in state EndRoot Element would result in an invalid XML document. Make sure that the ConformanceLevel setting is set to ConformanceLevel.Fragment or ConformanceLevel.Auto if you want to write an XML fragment.
We see that there are 4 employee elements with 4 sub-elements in each. It does not have attributes on the elements, but is a properly-formed document.
<?xml version="1.0" encoding="utf-8"?> <Employees> <Employee> <ID>1</ID> <FirstName>David</FirstName> <LastName>Smith</LastName> <Salary>10000</Salary> </Employee> <Employee> <ID>3</ID> <FirstName>Mark</FirstName> <LastName>Drinkwater</LastName> <Salary>30000</Salary> </Employee> <Employee> <ID>4</ID> <FirstName>Norah</FirstName> <LastName>Miller</LastName> <Salary>20000</Salary> </Employee> <Employee> <ID>12</ID> <FirstName>Cecil</FirstName> <LastName>Walker</LastName> <Salary>120000</Salary> </Employee> </Employees>
Dispose
If you use the using
-statement on an XmlWriter
, the Dispose
method will be called. In the Dispose
method, we see that the Close
method is called.
Close()
if you use using—otherwise, you should call Close
.using
-statement, which wraps all the XmlWriter
code, is important to remember..method family hidebysig newslot virtual instance void Dispose(bool disposing) cil managed { // Code size 19 (0x13) .maxstack 8 ... IL_000c: ldarg.0 IL_000d: callvirt instance void System.Xml.XmlWriter::Close() IL_0012: ret } // end of method XmlWriter::Dispose
This tutorial used XmlWriter
with the using
-statement. And it invoked several methods on the type. We looked at some problems, and checked XML Notepad and the output XML.