2. The XML Text Reader
Reading the XML document in your code is just as easy
with the corresponding XmlTextReader class. The XmlTextReader moves
through your document from top to bottom, one node at a time. You call
the Read() method to move to the next node. This method returns True if
there are more nodes to read or False once it has read the final node.
The current node is provided through the properties of the XmlTextReader
class, such as NodeType and Name.
A node is a
designation that includes comments, whitespace, opening tags, closing
tags, content, and even the XML declaration at the top of your file. To
get a quick understanding of nodes, you can use the XmlTextReader to run
through your entire document from start to finish and display every
node it encounters. The code for this task is as follows:
Dim file As String = Path.Combine(Request.PhysicalApplicationPath, _
"App_Data\SuperProProductList.xml")
Dim fs As New FileStream(file, FileMode.Open)
Dim r As New XmlTextReader(fs)
' Use a StringWriter to build up a string of HTML that
' describes the information read from the XML document.
Dim writer As New StringWriter()
' Parse the file, and read each node.
Do While r.Read()
writer.Write("<b>Type:</b> ")
writer.Write(r.NodeType.ToString())
writer.Write("<br />")
' The name is available when reading the opening and closing tags
' for an element. It's not available when reading the inner content.
If r.Name <> "" Then
writer.Write("<b>Name:</b> ")
writer.Write(r.Name)
writer.Write("<br />")
End If
' The value is when reading the inner content.
If r.Value <> "" Then
writer.Write("<b>Value:</b> ")
writer.Write(r.Value)
writer.Write("<br />")
End If
If r.AttributeCount > 0 Then
writer.Write("<b>Attributes:</b> ")
For i As Integer = 0 To r.AttributeCount - 1
writer.Write(" ")
writer.Write(r.GetAttribute(i))
writer.Write(" ")
Next
writer.Write("<br />")
End If
writer.Write("<br />")
Loop
fs.Close()
' Copy the string content into a label to display it.
lblXml.Text = writer.ToString()
To test this, try the XmlText.aspx page included with the online samples. It produces the result shown in Figure 2.
The following is a list of all the nodes that are found, shortened to include only one product:
Type: XmlDeclaration
Name: xml
Value: version="1.0"
Attributes: 1.0
Type: Element
Name: SuperProProductList
Type: Comment
Value: This file generated by the XmlTextWriter class.
Type: Element
Name: Product
Attributes: 1 Chair
Type: Element
Name: Price
Type: Text
Value: 49.33
Type: EndElement
Name: Price
Type: EndElement
Name: Product
Type: EndElement
Name: SuperProProductList
If you use the indentation trick described earlier (in the "Formatting Your XML" sidebar), you'll see additional nodes that represent the bits of whitespace between elements.
In a typical application, you would need to go
fishing for the elements that interest you. For example, you might read
information from an XML file such as SuperProProductList.xml and use it
to create Product objects based on the Product class shown here:
Public Class Product
Public Property ID() As Integer
Public Property Name() As String
Public Property Price() As Decimal
End Class
Nothing is particularly special about this class—all
it does is allow you to store three related pieces of information
(price, name, and ID). Note that this class uses automatic properties
rather than public member variables, so its information can be displayed
in a web page with ASP.NET data binding.
A typical application might read data from an XML
file and place it directly into the corresponding objects. The next
example (also a part of the XmlWriterTest.aspx page) shows how you can
easily create a group of Product objects based on the
SuperProProductList.xml file. This example uses the generic List
collection, so you'll need to import the System.Collections.Generic
namespace.
' Open a stream to the file.
Dim file As String = Path.Combine(Request.PhysicalApplicationPath, _
"App_Data\SuperProProductList.xml")
Dim fs As New FileStream(file, FileMode.Open)
Dim r As New XmlTextReader(fs)
' Create the collection of products.
Dim Products As New List(Of Product)()
' Loop through the products.
Do While r.Read()
If r.NodeType = XmlNodeType.Element And r.Name = "Product" Then
Dim NewProduct As New Product()
NewProduct.ID = Int32.Parse(r.GetAttribute("ID"))
NewProduct.Name = r.GetAttribute("Name")
' Get the rest of the subelements for this product.
Do Until r.NodeType = XmlNodeType.EndElement
r.Read()
' Look for Price subelement.
If r.Name = "Price" Then
Do Until (r.NodeType = XmlNodeType.EndElement)
r.Read()
If r.NodeType = XmlNodeType.Text Then
NewProduct.Price = Val(r.Value)
End If
Loop
End If
' We could check for other Product nodes
' (like Available, Status, etc.) here.
Loop
' Add the product to the list.
Products.Add(NewProduct)
End If
Loop
fs.Close()
' Display the retrieved document.
gridResults.DataSource = Products
gridResults.DataBind()
2.1. Dissecting the Code . . .
This code uses a nested looping structure.
The outside loop iterates over all the products, and the inner loop
searches through all the child elements of <Product>. (In this
example, the code processes the <Price> element, and ignores
everything else.) The looping structure keeps the code well organized.
The
EndElement node alerts you when a node is complete and the loop can
end. Once all the information is read for a product, the corresponding
object is added into the collection.
All
the information is retrieved from the XML file as a string. Thus, you
need to use methods like Int32.Parse() to convert it to the right data
type.
Data binding is used to display the
contents of the collection. A GridView set to generate columns
automatically creates the table shown in Figure 3.
NOTE
The XmlTextReader
provides many more properties and methods. These additional members
don't add functionality; they allow for increased flexibility. For
example, you can read a portion of an XML document into a string using
methods such as ReadString(), ReadInnerXml(), and ReadOuterXml(). These
members are all documented in the class library reference in the Visual
Studio Help.