Writing XML Files Using the XmlTextWriter Class

This first of a multi-part series on using the .NET XML classes begins with the logical first step: programmatically creating and writing XML files or documents. From there, future articles will cover the tasks of sequentially reading XML files, writing a simple XML maintenance application, and using the XML DOM (Document Object Model) classes for a finer level of control over more sophisticated file schemas.

Note: The series assumes that you are familiar with the basics of XML. If you are new to XML, read one of the many fine tutorials on the subject first and then return to this document.

XmlTextWriter Basics

The XmlTextWriter class supports a non-cached, forward-only means of writing W3C-standard XML data to a file. As a result, it is typically used in cases where the application needs to generate an entire XML file from start to finish. If your application needs dynamic access to specific parts of a file, you will need to use the XmlDocument class (which a future article will cover). Also, the XmlTextWriter class performs no validation on the data being written. Therefore, it is up to the programmer to ensure that any data passed to the XmlTextWriter class is well formed, or standard, XML.

Generating an XML File

You take the following four basic steps to generate a properly formed XML file with the XmlTextWriter class:

  1. Instantiate an XmlTextWriter object.
  2. Write the XML declaration node.
  3. Write the data.
  4. Close the file and perform cleanup.

Instantiate an XmlTextWriter Object

The XmlTextWriter constructor has three distinct versions:

XmlTextWriter(TextWriter* textWriter);
XmlTextWriter(Stream* inputStream, Encoding* encoding);
XmlTextWriter(String* fileName, Encoding* encoding);

The first two constructors are useful in situations where you already have a stream object associated with a file. The third constructor allows the code to specify the file name. With this constructor, you must ensure that the file exists and handle any file-level exceptions that the XmlTextWriter throws if it encounters problems with the specified file.

Write the XML Declaration Node

You write the XML declaration node with the XmlTextWriter::WriteStartDocument method. It is the first line you see in (well-formed) XML files. This node includes such information as the XML version and encoding method used. Here's an example of that node:

<?xml version="1.0" encoding="UTF-8" ?>

Some files do not include this node, but the W3C standards dictate its inclusion. Therefore, you should create a declaration node if your file will be used by other applications or shared with other users who expect standard XML data.

The WriteStartDocument method has only two overloads:

WriteStartDocument();
WriteStartDocument(bool standAlone);

The first version of this method writes the node with only the version attribute (as seen in the previous example), whereas the second version includes a Boolean value indicating whether you want the standalone attribute explicitly stated and what you want its value to be. Here are a couple of examples of that (where the encoding attribute is based on your locale):

writer->WriteStartDocument();
// produces <?xml version="1.0" encoding="us-ascii"?>

writer->WriteStartDocument(true);
// produces <?xml version="1.0" encoding="us-ascii" standalone="yes"?>

writer->WriteStartDocument(false);
// produces <?xml version="1.0" encoding="us-ascii" standalone="no"?>

Write the Data

Once you've written the declaration node, you can write the nodes and attributes that constitute your file's data. There are about a dozen XmlTextWriter methods, so I won't delve into the details of all of them. Rather, I discuss the higher-level process of writing nodes and attributes and give the following examples:

  • Starting and ending an element–Keeping in mind that the XmlTextWriter is a forward-only writer, you have to write each part of the file as that file will appear. Therefore, if you want to output an element containing an element, an attribute, and a value, you must make the appropriate calls in that order. To begin that, call the XmlTextWriter::WriteStartElement method. From there, make calls to methods to insert attributes, values, and other elements. Indicate that the element is to be closed via a call to XmlTextWriter::WriteEndElement:
    writer->WriteStartElement(S"Article");
    // write xml to appear within this element
    writer->WriteEndElement();
    
  • Writing attributes–Within a WriteStartElement/WriteEndElement pair, you can write a given element's attributes. This is done via the XmlTextWriter::WriteAttributeString method. The following snippet writes an attribute called "lang" with a value of "EN" to the element currently being written:
    writer->WriteAttributeString(S"lang", S"EN");
  • Writing an element's value–There are several different specialized methods for writing the value of the current element. Of these, the most commonly used is the XmlTextWriter::WriteString method, which writes the specified value to the current element:
    writer->WriteString(S"Writing XML Files using the
                          XmlTextWriterClass");
    
  • Writing CDATA–If an XML parser will read the data you write, you have to be careful not to break any rules regarding what that data can include. Otherwise, it will confuse the parser. In such cases, specify that the element type is CDATA and write it using the XmlTextWriter::WriteCData method:
    writer->WriteCData(S"http:\\\\www.test url&var=value");
  • Writing a simple element without attributes or nested elements–If you need to write an element containing a value and that element doesn't have any other information associated with it (such as attributes or other nested elements), you can use the XmlTextWriter::WriteElementString method:
    writer->WriteElementString(S"Author", S"Tom Archer");

Writing XML Files Using the XmlTextWriter Class

Close the File and Perform Cleanup

Once you've finished writing the XML data, close the document. This is typically done with the following calls:

writer->WriteEndDocument();
writer->Flush();
writer->Close();

Example

Taking the methods outlined in the previous section, the following bit of C++ calls various XmlTextWriter methods to generate a simple XML file:

XmlTextWriter* writer = new XmlTextWriter(S"test.xml", Encoding::ASCII);

writer->WriteStartDocument(true);

  writer->WriteStartElement("Article");
    writer->WriteElementString(S"Author", S"Tom Archer");

    writer->WriteStartElement(S"Title");
      writer->WriteAttributeString(S"lang", S"EN");
      writer->WriteString(S"Writing XML Files using the XmlTextWriterClass");
    writer->WriteEndElement();

    writer->WriteStartElement(S"URL");
      writer->WriteCData(S"http:\\\\www.test url&var=value");
    writer->WriteEndElement();
  writer->WriteEndElement();

writer->WriteEndDocument();

writer->Flush();
writer->Close();

This C++ code will generate the XML shown in Figure 1.

[XmlCreatingFile.jpg]

Figure 1: XML Generated By Example C++

Looking Ahead

This first installment of the series on using the .NET XML classes demonstrated how easy it is to generate a valid XML file with Managed C++ and the XmlTextWriter class. The next article proceeds to the next logical step: using the XmlTextReader class.



About the Author

Tom Archer - MSFT

I am a Program Manager and Content Strategist for the Microsoft MSDN Online team managing the Windows Vista and Visual C++ developer centers. Before being employed at Microsoft, I was awarded MVP status for the Visual C++ product. A 20+ year veteran of programming with various languages - C++, C, Assembler, RPG III/400, PL/I, etc. - I've also written many technical books (Inside C#, Extending MFC Applications with the .NET Framework, Visual C++.NET Bible, etc.) and 100+ online articles.

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: December 11, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT Market pressures to move more quickly and develop innovative applications are forcing organizations to rethink how they develop and release applications. The combination of public clouds and physical back-end infrastructures are a means to get applications out faster. However, these hybrid solutions complicate DevOps adoption, with application delivery pipelines that span across complex hybrid cloud and non-cloud environments. Check out this …

  • On-demand Event Event Date: October 29, 2014 It's well understood how critical version control is for code. However, its importance to DevOps isn't always recognized. The 2014 DevOps Survey of Practice shows that one of the key predictors of DevOps success is putting all production environment artifacts into version control. In this webcast, Gene Kim discusses these survey findings and shares woeful tales of artifact management gone wrong! Gene also shares examples of how high-performing DevOps …

Most Popular Programming Stories

More for Developers

RSS Feeds