ONDotNet.com    
 Published on ONDotNet.com (http://www.ondotnet.com/)
 See this if you're having trouble printing code examples


Liberty on Whidbey

XML DataSource Controls in .NET 2.0

by Jesse Liberty
04/18/2005

As noted in previous columns, .NET 2.0 pushes most of ADO.NET into the frameworks level, and provides you with various DataSource controls to make accessing data easy. With the XML DataSource control, you can bind to an XML document just as easily as you bind to tables in a database. If the XML document you load is hierarchical, the data is exposed hierarchically, which makes it ideal to map an XML document to a TreeView control.

To get started, fire up Visual Studio 2005 (or Visual Web Developer) and create a new web site named BindingToXML. Create a new item, an XML file named BookList.xml, and add it to the project, as shown in Example 1:


<?xml version="1.0" encoding="utf-8" ?>
<Books>
  <book Name="Programming C#">
    <Author Name = "Jesse Liberty" />
    <Publisher PublisherName = "OReilly Media" />
  </book>
  <book Name="Programming ASP.NET">
    <Author Name = "Jesse Liberty" />
    <Author Name = "Dan Hurwitz" />
    <Publisher PublisherName = "OReilly Media" />
  </book>
  <book Name="Visual C# Notebook">
    <Author Name = "Jesse Liberty" />
    <Publisher PublisherName = "OReilly Media" />
  </book>
</Books>

Add an XMLDataSource to your Default.aspx page. You can do this by dragging one onto your form from the Toolbox, or, interestingly, by dragging one from the Toolbox right into the Source view. Add an attribute, DataFile, and set its value to the name of your XML file, as shown in Figure 1:

Figure 1
Figure 1.

You are now ready to add a TreeView control and bind it to this data source. Switch to design mode and drag a TreeView control onto the form. (The TreeView control is usually found under the Navigation section of the toolbox.)

The smart tag allows you to choose the XMLDataSource you just created as the TreeView's data source.

Figure 2
Figure 2.

Click on Auto Format in the smart tag, and choose Windows Help as the format style, as shown in Figure 3:

Figure 3
Figure 3.

Click on Edit TreeNode Databindings to open the TreeView DataBindingsEditor. Set the DataMember for each member in the hierarchy that you want to display (in this case, book, Author, and Publisher), and set the TextField to tell the TreeView which text to use for each DataMember, as shown in Figure 4:

Figure 4
Figure 4.

The DataBindings Editor creates HTML that you can see in source view:


<asp:TreeView ID="TreeView1" runat="server" 
DataSourceID="XmlDataSource1" ImageSet="WindowsHelp">
    <ParentNodeStyle Font-Bold="False" />
    <SelectedNodeStyle BackColor="#B5B5B5" 
    Font-Underline="False" HorizontalPadding="0px"
    VerticalPadding="0px" />
    <DataBindings>
        <asp:TreeNodeBinding DataMember="book" TextField="Name" />
        <asp:TreeNodeBinding DataMember="Author" TextField="Name" />
        <asp:TreeNodeBinding DataMember="Publisher" TextField="PublisherName" />
    </DataBindings>
    <NodeStyle Font-Names="Tahoma" Font-Size="8pt" 
    ForeColor="Black" HorizontalPadding="5px"
        NodeSpacing="0px" VerticalPadding="1px" />
    <HoverNodeStyle Font-Underline="True" ForeColor="#6666AA" />
</asp:TreeView>

Note that for each binding, the DataMember corresponds to the DataBinding you added (book, Publisher, Author) and the TextField corresponds to the value you placed in the TextField property, which in turn corresponds to the AttributeName in the XML.

Run the application and the data in the XML document is bound to the control, as shown in Figure 5:

Figure 5
Figure 5.

You can easily modify how the tree is displayed by choosing a different scheme in AutoFormat. For example, if you choose MSDN, the books are replaced by the MSDN minus and plus signs. In either mode, each entry is a link, as shown in Figure 6:

Figure 6
Figure 6.

XPath

.NET 2.0 provides a new, much improved XPathDocument class that offers a cursor-based XML reader that is both more flexible than either XMLWriter or XMLReader and more efficient (and faster) than XMLDocument. With XPathDocument, it is not necessary for the entire XML document to be loaded into memory, and XPathDocument supports data binding. You can display the XPathDocument in a control just by setting the DataSource property to point to the XPathDocument.

This time create a Windows application named XPATH. Add an XML document, named BookList.xml, but note that this version of BookList.xml is slightly different from the previous version. The book element does not have an attribute for the BookName; instead, the book name is a sub-element of book.


<?xml version="1.0" encoding="utf-8" ?>
<Books>
  <book>
    <BookName>Programming C#</BookName>
    <Author>Jesse Liberty</Author>
    <Publisher>OReilly Media</Publisher>
  </book>
  <book>
    <BookName>Programming ASP.NET</BookName>
    <Author>Jesse Liberty</Author>
    <Author>Dan Hurwitz</Author>
    <Publisher>OReilly Media</Publisher>
  </book>
  <book>
    <BookName>Visual C# Notebook</BookName>
    <Author>Jesse Liberty</Author>
    <Publisher>OReilly Media</Publisher>
  </book>
  <book>
    <BookName>Visual Basic 2005 Notebook</BookName>
    <Author>Matthew MacDonald</Author>
    <Publisher>OReilly Media</Publisher>
  </book>
</Books>

Return to the Windows form and add a label (named label1) and text box (named txtBookName). Then add a second label (named lblAuthor), and a button (named btnFind), as shown in Figure 7:

Figure 7
Figure 7.

Implement the Find button's click method with the following code, which will be explained below.


protected void btnFind_Click(object sender, EventArgs e)
{
  int numAuthors = 0;
  string authorName = string.Empty;
  
  // get the file as an XPathDocument
  XPathDocument document = 
    new XPathDocument("..\\..\\BookList.xml");
  
  // Get a navigator over the document
  XPathNavigator navigator = document.CreateNavigator();
  
  // move to books
  navigator.MoveToFirstChild();   
  navigator.MoveToFirstChild();   
    
  do  // look at each node
  {
    // move to entries under book
    navigator.MoveToFirstChild(); 
    
    do  // look at each sub entry under book
    {
      // if you match the book name, you found the book we want
      if (navigator.Value == txtBookName.Text)
      {
        // moving through the name, author, publisher
        do               
        {
           // if you found the author tag, 
           // get all the authors
           if (navigator.Name == "Author")
           {
              if (++numAuthors > 1)   // make a list
              {
                 authorName += ", ";
              }
              authorName += navigator.Value;
           }
        } while (navigator.MoveToNext());   
      }               // end if we found the book

      // go to the entry under book
    } while (navigator.MoveToNext());   

    // done with this book, go up a level
    navigator.MoveToParent();         

  } 

// go to next book
  while (navigator.MoveToNext());      
  
    if (numAuthors == 0)
    {
      authorName = "Not Found";
    }
    lblAuthor.Text = authorName;
  }
}

Be sure to add this using statement at the top of your file:

using System.Xml.XPath;

The best way to see how this code works is to step through it in the debugger. Place a break point on this line:


XPathDocument document = new XPathDocument("..\\..\\BookList.xml");

Because the default place to look for the XML file is in the debug directory, you are setting the relative path to where the source code is held. Run the debugger. Enter the name of a book (e.g., "Programming ASP.NET") and click Find. The debugger stops at your break point. Hit F10 and hover over the document. You'll find that you have an object of the type XPathDocument. Hit F10 to get the navigator. Open the watch window and add three entries, as shown in Figure 8:

Figure 8
Figure 8.

Move your cursor so that it is on this line of code:

navigator.MoveToFirstChild();

and the Navigator.Name field is blank. Hit F10 and the Navigator.Name value changes to "Books". You want to go one more level down. Hit F10 and the Navigator.Name value changes to "book". Aha! You are now examining a book node, just what you want.

Enter the do loop and execute the MoveToFirstChild command. This sets the Navigator.Name value to "BookName" and the NavigatorValue to "Programming C#"--not the book you are looking for, so the if statement fails, as shown in Figure 9:

Figure 9
Figure 9.

Hit F10 to cycle through the do loop. Finally, you've looked at all the fields for that book and you hit this line:

navigator.MoveToParent();

This brings you back up to the book level. Continue to hit F10 and you move to the next book and then enter the do loop again, where you move to the first child of that book. You are now ready to examine the book name, and this time you have the right book. The if statement succeeds, so you enter the innermost do loop to iterate through the entries for this book.

When the Navigator.Name field is equal to "Author," you have the right author for the right book, and so you can add to the authorName string (the final if statement just puts commas between names for multiple authors). When you exit all of this code, you've grabbed the names for the authors of the chosen book and you've displayed it in the label, as shown in Figure 10:

Figure 10
Figure 10.

Jesse Liberty is a senior program manager for Microsoft Silverlight where he is responsible for the creation of tutorials, videos and other content to facilitate the learning and use of Silverlight. Jesse is well known in the industry in part because of his many bestselling books, including O'Reilly Media's Programming .NET 3.5, Programming C# 3.0, Learning ASP.NET with AJAX and the soon to be published Programming Silverlight.

.NET & XML

Related Reading

.NET & XML
By Niel Bornstein

Read more Liberty on Whidbey columns.

Return to ONDotnet.com

Copyright © 2009 O'Reilly Media, Inc.