In previous lessons, we learned to process XML files
using the Document Object Model as implemented by the XmlDocument
class. To go further and make XML friendlier, the .NET Framework provides
many other classes for different purposes, allowing you to create and manage
nodes from custom .NET classes.

Besides the XmlDocument and the derived classes
of XmlNode, the .NET Framework provides the XmlTextWriter
class, which is derived from XmlWriter. The XmlTextWriter
class works in a top-down approach to create, or deal with, the contents of
an XML file. This class writes an XML node and moves down without referring
back:

This means that, once you have created a node using the
XmlTextWriter, you have no way of referring back to it.

To use an XmlTextWriter object, first declare a
variable of the type of this class and initialize it using one of its three
constructors.

If you had already created a Stream-based object
such as declaring a variable of type FileStream but you didn't define
an encoding scheme, you can pass the Stream-based object to an
XmlTextWriter but you must take this time to specify the encoding
scheme. To support this concept, the XmlTextWriter provides a
constructor with the following syntax:

public XmlTextWriter(Stream w, Encoding encoding);

The first argument of this constructor can be a
Stream-derived variable. The second argument specifies the encoding
scheme that would be applied. The default is UTF-8. Based on this, if you
want to use the UTF-8 encoding scheme, you can pass it or pass the argument
as 0. If you want to use another encoding scheme, pass it to the
constructor.

To work from scratch, that is, to initiate a file with
manually-created nodes, you can pass the desired name of the file to the
XmlTextWriter constructor using the following syntax:

public XmlTextWriter(string filename, Encoding encoding);

In this case, you must provide the name of, or path to,
the file, whose content you are creating, as the first argument. You must
pass the desired encoding scheme as the second argument. Here is an example:

Eventually, when you have finished using the
XmlTextWriter object, you must free the memory it was using by calling
the XmlTextWriter.Flush() method. To release the resources that the
object was using, call the XmlTextWriter.Close() method. Here is an
example:

Declaring an XmlTextWriter variable allows you to
indicate that you intend to create a new XML file. With the variable ready,
you can start writing the file's content. As mentioned in previous lessons,
an XML file starts at the top with an XML declaration. To create this
declaration, you can call the XmlTextWriter.WriteStartDocument()
method. This method is overloaded with two versions. The syntax of one of
them is:

public void WriteStartDocument();

This method creates a declaration, sets the XML version
to 1.0, and includes the encoding scheme you specified in the constructor.
Here is an example:

Between the XML declaration and the end of the file,
that is, between the call to XmlTextWriter.WriteStartDocument() and
the call to XmlTextWriter.WriteEndDocument() methods, you can create
the necessary nodes of the file. As reviewed in previous lessons, the most
regular node of an XML file is the element. To create an element, the
XmlTextWriter class provides the WriteStartElement() method that
is overloaded with various versions. One of the versions of this method and
that is inherited from the XmlWriter class uses the following syntax:

public void WriteStartElement(string localName);

This method takes as argument the name of the element
that will be created. Here is an example:

As you can see from the result, a single or the first
call to the WriteStartElement() method creates the root element that
is required for every XML file. This means that, after this (first) call but
before its corresponding WriteEndElement() call, you can create the
necessary nodes that you want to include as part of the file.

Creating the Child Elements of the Root

To help you create child elements of the root node, you
can keep calling the XmlTextWriter.WriteStartElement() method as
necessary and appropriately closing it. Here is an example:

If you call the XmlTextWriter.WriteStartElement()
method and you want the element to have a value, remember to call the
XmlTextWriter.WriteString() method, and then call the
XmlTextWriter.WriteEndElement() method. An alternative is to call the
XmlWriter.WriteElementString() method that comes in two versions. The
syntax of one of these versions is:

public void WriteElementString(string localName, string value);

The first argument to this method is the name of the
element that will be created. The second argument is the value of the
element. This method creates and closes its element. Here is an example:

If you are creating a text-intensive document and you
want to save it as an XML file, for example if you have declared a variable
of type TextWriter-derived class (such as StringWriter or
StreamWriter), you can use that file to initialize the XmlTextWriter
variable. To support TextWriter documents, the XmlTextWriter
provides a constructor with the following syntax:

public XmlTextWriter(TextWriter w);

This constructor expects as argument TextWriter-based
object. This means that you should have defined the TextWriter object
prior to passing it to this constructor. This also implies that the
TextWriter was used to specify the encoding scheme that would be used.
Here is an example:

Once an XML file exists, you can read it to retrieve the
values of its nodes. To support opening an XML file and reading its
contents, the .NET Framework provides the XmlTextReader class that is
derived from the XmlReader class. The XmlTextReader class is
equipped with all the necessary properties and methods to explore the
contents of an XML file.

Like XmlTextWriter, the XmlTextReader
class reads a file from top to bottom without going back up once it has
passed a node:

This means that, when using the XmlTextReader
class to read an XML file, once you have read a node and moved down the
file, you cannot refer back to the previous node and you cannot access a
previous node: once you have passed a node, you cannot access it anymore.

Using and XML Text Reader

To use an XML text reader, declare a variable of type
XmlTextReader and initialize it with one of its constructors. This class
is equipped with 14 constructors. If you want to open a file whose name or
path you know, use the following constructor:

public XmlTextReader(string url);

This constructor takes as argument the name of, or path
to, an XML file. If the file is found, it would be opened. If the file
doesn't exist or there is an error in the string that specifies its path,
the compiler would throw an XmlException exception.

Reading Nodes

After declaring an XmlTextReader variable, you
can start reading the content of the file. To support this, you can call the
XmlTextReader.Read() method. Its syntax is:

public override bool Read();

As mentioned previously, the file is read from top to
bottom. Based on this, when you call the Read() method, it reads the
first node, moves to the next, and so on until it reaches the end of the
file. While reading the file, every time this method reaches a node, you can
find out what type of node it is by checking the XmlTextReader.NodeType
property. This can help you take a specific action if the reached node meets
a certain criterion.

As reviewed in our introductions to XML, each node has a
name and possibly a value. You can find out the name of a node by checking
the XmlTextReader.Name property. To know the value of a node,
retrieve its XmlTextReader.Value property.

Practical Learning: Reading the Elements of an XML File

Display the form.From the Dialogs section of the Toolbox, click
OpenFileDialog and click the form

If you were asked to examine this file, you can see that
its crowded words make it difficult to read. To include a white space when
writing to the file, you can call the XmlTextWriter.WriteWhiteSpace()
method. Its syntax is:

public override void WriteWhitespace(string ws);

Besides white spaces, indentation consists of setting
empty spaces on the left of child nodes to make the file easier to read.
Based on this, indentation is not a requirement but a convenience. While the
WriteWhiteSpace() method allows you to explicitly create a white
space in the file, the XmlTextWriter class is equipped with the
Formatting property. This property is a value of the Formatting
enumeration. The Formatting enumeration has two members. The
Indented value ensures that each child node would be indented from its
parent.

If you manually create an XML file, whether using
Notepad, Visual Studio, or another text editor, you can indent the nodes as
you see fit. To let the compiler know that you want the nodes to be
indented, assign the Formatting.Indented member to its Formatting
property. Here is an example:

If you manually create an XML file, you can specify the
number of empty spaces on the left of a node by pressing the Space bar a few
times before typing the node. Most people use 2 or 4 characters for the
indentation. If you are programmatically creating the file, to specify the
number of characters that should be used during indentation, assign the
desired integer to the XmlTextWriter.Indentation property. If you
don't use this property, the compiler would use two characters. You can also
find out the number of characters used for indentation by retrieving the
value of this property.

As mentioned above, indentation consists of entering
white spaces on the left of child nodes. Instead of empty spaces, if you
want to use another character, assign it to the XmlTextWriter.IndentChar
property.

Notice that if you open a repair order, change it and try to save
it, the application would create a new repair order with a new receipt
number.Configure the form so that, if a repair order was previous
opened then changed, if the user saves it, the current repair order
would be saved, using its own receipt number instead of generating a new
receipt number