Reading XML Files Sequentially - Page 3
       by kirupa  |  18 January 2007

In the previous page, I described how to approach reading an XML file, and then provided some code and began explaining what the code does. This page picks up from where we last left off.

XmlNodeType nodeType = reader.NodeType;

One of the goals we mentioned was to figure out what the current node actually is. To classify our node, we use the XmlNodeType class. In the above line, I determine the node type by accessing our reader obect's NodeType property and storing that result in our XmlNodeType object called nodeType.


switch (nodeType)
{
case XmlNodeType.Element:
  if (reader.HasAttributes)
  {
  for (int i = 0; i < reader.AttributeCount; i++)
  {
  reader.MoveToAttribute(i);
  }
  Console.WriteLine("Attribute is {0} with Value {1}: ",   reader.Name, reader.Value);
  }
  break;
case XmlNodeType.Text:
  Console.WriteLine("Value is: " + reader.Value);
  break;
}

Once I store the node type in the nodeType object, I use a switch/case statement to determine whether our node is of type Element or Text. Switch/case statements are just another way of writing conditional statements without using if/else statements.


Console.WriteLine("Element name is {0}", reader.Name);

If our node is an element, I can access the element's name by calling the Name property from our reader object. The element names in our example would be menu, parent, child, title, and link.


if (reader.HasAttributes)
{
for (int i = 0; i < reader.AttributeCount; i++)
{
reader.MoveToAttribute(i);
}
Console.WriteLine("Attribute is {0} with Value {1}: ", reader.Name, reader.Value);
}

As explained in the intro, some elements may contain attributes. We check to see if this element contains an attribute by using the aptly named HasAttributes property on our reader object.


if (reader.HasAttributes)
{
for (int i = 0; i < reader.AttributeCount; i++)
{
reader.MoveToAttribute(i);
Console.WriteLine("Attribute is {0} with Value {1}: ", reader.Name, reader.Value);
}
}

If our element actually contains attributes, you can use a for loop to navigate through each attribute. The total number of attributes your element stores is noted by your reader object's AttributeCount property.

Something really unique is that it's not good enough to just know the index position of where your next attribute is. You need to actually move to that particular attribute by using the reader object's MoveToAttribute property. To link an earlier analogy I used, you physically move your magnifying glass to the next node. Once you have moved to the new location, you can access the Name and Value properties like you did before.


case XmlNodeType.Text:
  Console.WriteLine("Value is: " + reader.Value);
  break;

We reach the second of our two cases when our element is an xml node of type Text. When dealing with text content, you don't have much more work to do. You can simply access the text value using reader.Value.


Quick Review + Alternate Approach
While it looked like there was a lot of code, what the code actually does is fairly simple. The most important thing to keep in mind is that the above approach loops through each node in your code. You cannot, at least in the implementation I presented, look at a previous or future nude from your current location. That explains why when you wanted to access the attribute value, you first had to explicitly move to the next element before accessing that element's value.

The code I provided so far is pretty generic. There may be situations where you want to only access certain elements from your XML file. The following code highlights how you can access values from only elements whose names you specify:

XmlTextReader reader = new XmlTextReader("C:\\links.xml"));
while (reader.Read())
{
XmlNodeType nodeType = reader.NodeType;
if (nodeType == XmlNodeType.Element)
{
switch(reader.Name) {
case "title":
  Console.WriteLine("TITLE: " + reader.ReadString());
  break;
case "link":
  Console.WriteLine("LINK: " + reader.ReadString());
  break;
case "parent":
  reader.MoveToAttribute(0);
  Console.WriteLine("PARENT: " + reader.Value);
  break;
}
}
}

The above code is similar to our earlier code except my switch/case statement checks for the actual element name instead of checking whether the node is an Element or Text. Also, notice that when I am checking for attributes in the parent element, I am again using the MoveToAttribute method and passing in an index number, but since I know exactly how our XML file is structure, I am bypassing the for loop and substituting a value of 0 to our MoveToAttribute method directly.


Just a final word before we wrap up. If you have a question and/or want to be part of a friendly, collaborative community of over 220k other developers like yourself, post on the forums for a quick response!

Kirupa's signature!

 

1 | 2 | 3




SUPPORTERS:

kirupa.com's fast and reliable hosting provided by Media Temple.