< Reading & Writing XML 1 | Main | Reading & Writing XML 3 >


 

 

Reading and Writing XML 2

 

 

What we have in this page?

 

  1. Parsing XML with XmlTextReader...continue

 

The following exercise will show you how to read an XML document using the XmlTextReader class. Here’s the sample XML document (myxml.xml) used by this exercise and the other exercises in this module, which lists details of three volcanoes and which contains many common XML constructs. This file is put under the project’s debug directory so that no need for us to give a full path when running the program at command prompt.

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

<!-- Volcano data -->

<geology>

    <volcano name="Erebus">

        <location>Ross Island, Antarctica</location>

        <height value="3794" unit="m"/>

        <type>stratovolcano</type>

        <eruption>constant activity</eruption>

        <magma>basanite to trachyte</magma>

    </volcano>

    <volcano name="Hekla">

        <location>Iceland</location>

        <type>stratovolcano</type>

        <height value="1491" unit="m"/>

        <eruption>1970</eruption>

        <eruption>1980</eruption>

        <eruption>1991</eruption>

        <magma>calcalkaline</magma>

        <comment>The type is actually intermediate between crater row

    and stratovolcano types</comment>

    </volcano>

    <volcano name="Mauna Loa">

        <location>Hawaii</location>

        <type>shield</type>

        <height value="13677" unit="ft"/>

        <eruption>1984</eruption>

        <magma>basaltic</magma>

    </volcano>

</geology>

1.        Create a new Visual C++ CLR Console Application project named CppXmlTextReader.

 

 

 

 

Creating a new Visual C++ CLR Console Application project named CppXmlTextReader

 

2.        Add the following two lines to the top of CppXmlTextReader.cpp:

#using <System.xml.dll>

using namespace System::Xml;

 

Add header file and class namespace to the top of CppXmlTextReader.cpp

 

The code for the XML classes lives in System.xml.dll, so include it via a #using directive. It’s also going to be easier to use the classes if you include a using directive for the System::Xml namespace, as shown in the preceding code.

 

3.        Because you’re going to supply the name of the XML document when you run the program from the command line, change the declaration of the main() function to include the command-line argument parameters, as follows:

// Get the command line arguments

array<String^>^args = Environment::GetCommandLineArgs();

 

Changing the declaration of the main() function to include the command-line argument parameters

 

4.        Add this code to the start of the main() function to check the number of arguments and save the path:

// Check for required arguments

if (args->Length < 2)

{

   Console::WriteLine(L"Usage: CppXmlTextReader path");

   return -1;

}

 

String^ path = gcnew String(args[1]);

 

Adding code to the start of the main() function to check the number of arguments and save the path

 

5.        Now that you’ve got the path, create an XmlTextReader to parse the file.

try

{

   // Create the reader...

   XmlTextReader^ rdr = gcnew XmlTextReader(path);

   Console::WriteLine("Xml reader is created...");

}

catch (Exception^ pe)

{

   Console::WriteLine(pe->ToString());

}

 

Creating an XmlTextReader to parse the file

 

The XmlTextReader constructor takes the name of the document you want to parse. It’s a good idea to catch exceptions here because several things can go wrong at this stage, including passing the constructor a bad path name.

 

6.        You can build and run the application from the command line at this stage if you want to check that the file opens correctly.

 

Building and running the application from the command line to check that the file opens correctly

 

Note that XmlTextReader isn’t limited to reading from files. Alternative constructors let you take XML input from URLs, streams, strings, and other TextReader objects. Parsing the file simply means making repeated calls to the Read function until the parser runs out of XML to read. The simplest way to do this is to put a call to Read inside a while loop.

 

7.        Add this code to the end of the code inside the try block:

// Read nodes

while (rdr->Read())

{

   // do something with the data

}

Adding while loop code to the end of the code inside the try block

 

The Read function returns true or false depending on whether there are any more nodes to read.

 

8.        Each call to Read positions the XmlTextReader on a new node, and you query the NodeType property to find out which of the node types listed in the preceding table you are dealing with. Add the following code, which checks the node type against several of the most common types:

// Read nodes

while (rdr->Read())

{

   // do something with the data

   switch (rdr->NodeType)

   {

         case XmlNodeType::XmlDeclaration:

               Console::WriteLine(L"-> XML declaration");

               break;

         case XmlNodeType::Document:

               Console::WriteLine(L"-> Document node");

               break;

         case XmlNodeType::Element:

               Console::WriteLine(L"-> Element node, name={0}", rdr->Name);

               break;

         case XmlNodeType::EndElement:

               Console::WriteLine(L"-> End element node, name={0}", rdr->Name);

               break;

         case XmlNodeType::Text:

               Console::WriteLine(L"-> Text node, value={0}", rdr->Value);

               break;

         case XmlNodeType::Comment:

               Console::WriteLine(L"-> Comment node, name={0}, value={1}", rdr->Name, rdr->Value);

               break;

         case XmlNodeType::Whitespace:

               break;

         default:

               Console::WriteLine(L"** Unknown node type");

               break;

         }

   }

Every time a new node is read, the switch statement checks its type against members of the XmlNodeType enumeration. We haven’t included the cases for every possible node type, but only those that occur in the sample document.

You’ll notice that the Name and Value properties are used for some node types. Whether a node has a Name and a Value depends on the node type. For example, elements have names and can have values, and comments have a value (the comment text) but not names. Processing instructions normally have both names and values.

Also notice that nodes of type XmlNodeType::Whitespace are simply discarded. The myxml.xml file contains plenty of white space to make it readable to humans, but the CppXmlTextReader program isn’t really interested in white space, so the program prints nothing when it encounters a white space node.

 

9.        Build the application, and run it from the command line, giving the name of an XML file. The first few lines of the output should look like this:

 

 

 

 

The XmlTextReader program output example

 

The first node is the XML declaration at the top of the document, and it’s followed by a comment, whose value is the comment text. Each XML element in the document will produce a matching pair of Element and EndElement nodes, with the content of a node represented by a nested Text node. You can see that the nodes are presented to you in linear sequence, so if you want to keep track of the hierarchical structure of the document, you’re going to have to put code in place to do it yourself.

 

 

Part 1 | Part 2 | Part 3 | Part 4 | Part 5 | Part 6 | Part 7

 

 


< Reading & Writing XML 1 | Main | Reading & Writing XML 3 >