XML Processing with the XMLReader Object, Part 1 - Into the Real World
(Page 5 of 5 )
Now, if you're a developer, I'm sure the previous two examples would have raised your eyebrows a bit. The reason is simple: the examples I've shown you thus far have only studied the information structures in the XML file, completely ignoring the data contained within each attribute and element. In the real world, you're usually as concerned about the data within each element as about the element and attribute names.
That's where this next example comes in: it completes the circle, showing you how to process the data stored within each attribute and element. Take a look:
*Please note: A '/' (slash) at the end of any line indicates that the following line should be appended it, minus the '/'. - Editor
<%@ Page Language="C#" Debug="true"%>
<%@ Import namespace="System.Xml"%>
<html>
<head>
<script runat="server">
void Page_Load()
{
// variable to store Book ID
string strBookId = "";
// variable to store the
// Xml file (with location
string strXmlRdr = /
http://localhost/xmlpull/library.xml;
output.Text="<B>List of Books</B>";
// create an instance of the
// XmlDocument object
XmlTextReader objXmlRdr = /
new XmlTextReader(strXmlRdr);
objXmlRdr.WhitespaceHandling = /
WhitespaceHandling.None;
output.Text += "<ul>";
while(objXmlRdr.Read()) {
if(objXmlRdr.NodeType == /
XmlNodeType.Element) {
if(objXmlRdr.Name == "book") {
strBookId = /
objXmlRdr.GetAttribute("id");
}
if(objXmlRdr.Name=="title") {
output.Text += "<li>" + /
objXmlRdr.ReadString();
output.Text += "<ul>";
output.Text += "<li>ID - " /
+ strBookId + "</li>";
}
if(objXmlRdr.Name=="author") {
output.Text += "<li>Author - " /
+ objXmlRdr.ReadString() + /
"</li>";
}
if(objXmlRdr.Name=="description") {
output.Text += /
"<li>Description - " /
+ objXmlRdr.ReadString() /
+ "</li>";
}
if(objXmlRdr.Name=="price") {
output.Text += /
"<li>Price - " + /
objXmlRdr.GetAttribute("currency") /
+ " " + /
objXmlRdr.ReadString() + "</li>";
}
}
else if(objXmlRdr.NodeType ==
XmlNodeType.EndElement) {
if(objXmlRdr.Name == "book" ) {
output.Text += "</ul>";
output.Text += "</li>";
strBookId = "";
// reset the Book Id variable
}
}
}
output.Text += "</ul>";
// close the object and free
// up memory
objXmlRdr.Close();
}
</script>
</head>
<body>
<asp:label id="output" runat="server"/>
</body>
</html>
Load this example in the browser to see the list of books on the shelves of the library:

I'll begin by drawing your attention to the definition of a variable right at the beginning of the script:
<%
// variable to store Book ID
string strBookId = "";
%>
This variable will be used further down in the script to store the ID of the book.
Now, the process of reading the XML file starts with the Read() method of the XmlTextReader object. This next code snippet does the dirty work of processing the data that is read by the object.
<%
if(objXmlRdr.NodeType ==
XmlNodeType.Element) {
if(objXmlRdr.Name == "book") {
strBookId = objXmlRdr.GetAttribute("id");
}
if(objXmlRdr.Name=="title") {
output.Text += "<li>"
+ objXmlRdr.ReadString();
output.Text += "<ul>";
output.Text += "<li>ID - "
+ strBookId + "</li>";
}
if(objXmlRdr.Name=="author") {
output.Text += "<li>Author - "
+ objXmlRdr.ReadString()
+ "</li>";
}
if(objXmlRdr.Name=="description") {
output.Text += "<li>Description - "
+ objXmlRdr.ReadString() + "</li>";
}
if(objXmlRdr.Name=="price") {
output.Text += "<li>Price - "
+ objXmlRdr.GetAttribute("currency")
+ " "
+ objXmlRdr.ReadString()
+ "</li>";
}
} else if(objXmlRdr.NodeType ==
XmlNodeType.EndElement) {
if(objXmlRdr.Name == "book" ) {
output.Text += "</ul>";
output.Text += "</li>";
strBookId = "";
// reset the Book Id variable
}
}
%>
It all starts with a check to see if the current node is an element. As seen in the first example, this test returns true when the reader encounters the starting tag of an element in the XML file. Once this is confirmed, the script checks the name of each element that so that it can be processed appropriately. Note that you can also use the IsStartElement() method of the XmlTextReader object to check whether an element is indeed the opening element.
Element processing starts with the <book> element. Since I need the book ID, I've used the shortcut GetAttribute() method of the XmlTextReader object to fetch the value stored in the "id" attribute. If you know which attribute you want, this is a convenient way to avoid having to unnecessarily iterate through the collection of attributes, as demonstrated earlier. The ID retrieved is stored in the "strBookId" variable created earlier.
During the next pass, the script will encounter the other parameters associated with a particular book - its title, description, price, currency and so on. For each of these elements, the ReadString() method can be used to retrieve the text stored in the corresponding element.
Once a particular book has been dealt with, the "strBookId" variable must be reset for the next book in the library. A good place to do this is when the reader encounters the closing </book> element. How do you know when this happens? It's simple - just check if a particular node is a closing element with the "EndElement" property and if its name is </book>, and Bob's your uncle!
As you can see, once you know the basics of reading an XML file with the XMLReader, it's very easy to begin using its built-in constructs to extract and manipulate XML data to your precise needs. As an exercise to better understand how this works, I recommend taking your own XML markup and writing a similar script to extract element and attribute values from it.After all, practice makes perfect!
And that's about it for the first part of this tutorial. Over the last few pages, I introduced you to the XMLReader class, which offers developers an alternative way of processing an XML file or stream. Unlike the DOM, the XMLReader class offers developers a framework for sequential reading, making it possible to create faster, more streamlined XML applications.
At the beginning of this tutorial, I told you that the .NET Framework came with three important classes derived from the XMLReader abstract class. Over the course of the last few pages, I introduced you to the first and most-used of these, the XMLTextReader class, and showed you how to use it to process elements, attributes and the data within them. The second part of this article will deal more thoroughly with the remaining two classes, showing you how to validate an XML document against a DTD or XML Schema before processing it, and explaining how to handle errors in an XML document. Make sure you come back for that. Until then, be good!
Note: Examples are illustrative only, and are not meant for a production environment. Melonfire provides no warranties or support for the source code described in this article.
| DISCLAIMER: The content provided in this article is not warranted or guaranteed by Developer Shed, Inc. The content provided is intended for entertainment and/or educational purposes in order to introduce to the reader key ideas, concepts, and/or product reviews. As such it is incumbent upon the reader to employ real-world tactics for security and implementation of best practices. We are not liable for any negative consequences that may result from implementing any information covered in our articles or tutorials. If this is a hardware review, it is not recommended to open and/or modify your hardware. |