Kirk Evans Blog

.NET From a Markup Perspective

Use ASP.NET Data Binding to Bind Directly to XML (sans DataSet)

@kaevans

Use ASP.NET Data Binding to Bind Directly to XML (sans DataSet)

  • Comments 30

As I mentioned in my previous blog post about binding, any object that supports IEnumerable can be used as the DataSource for data binding in ASP.NET.  If you are processing XML, the XmlDocument class does not support IEnumerable (after all, it is a tree, not a list).  You can, however, bind to a set of nodes within an XML document, and use ASP.NET data binding to navigate through the rest of the document.

Suppose we have the XML document:

<Projects iProjectID ="13" vProjectName ="Plumber's Project" >
<Packages iPackageID ="36" vPackageName ="Bowser" >
<Modules iModuleID ="76" vModuleName ="Bob-omb Module" />
</Packages>
<Packages iPackageID ="40" vPackageName ="Princess" >
<Modules/>
</Packages>
</Projects>

We can select a set of nodes (called a node list) using XPath statements and the SelectNodes method of the XmlNode class. XmlNode.SelectNodes returns an object called an XmlNodeList, and this object is a collection that supports IEnumerable.  XmlNodeList, then, can be used as the DataSource for an ASP.NET data bound control.

using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Xml;

namespace ExampleWeb
{
  public class DataBindtoNodeSet : System.Web.UI.Page
  {
    protected System.Web.UI.WebControls.DataList DataList1;
  
    private void Page_Load(object sender, System.EventArgs e)
    {
      XmlDocument doc = new XmlDocument();
      doc.Load(Server.MapPath("data/xmlfile1.xml"));
      XmlNodeList nodes = doc.SelectNodes("Projects/Packages");
      
      DataList1.DataSource = nodes;
      DataList1.DataBind();
    }

    #region Web Form Designer generated code

    override protected void OnInit(EventArgs e)
    {
      InitializeComponent();
      base.OnInit(e);
    }
    
    private void InitializeComponent()
    {
      this.Load += new System.EventHandler(this.Page_Load);

    }
    #endregion

  }
}

You can see that the code-behind is really simply, the work is done in the Page_Load event.  We use the SelectNodes method to retrieve an XmlNodeList, and use that as the DataSource for our ASP.NET DataList control.

Here is the .aspx view of the code.

<%@ Page language="c#" Codebehind="DataBindtoNodeSet.aspx.cs" AutoEventWireup="false" Inherits="ExampleWeb.DataBindtoNodeSet" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
  <HEAD>
    <title>DataBindtoNodeSet</title>
    <meta name="GENERATOR" Content="Microsoft Visual Studio .NET 7.1">
    <meta name="CODE_LANGUAGE" Content="C#">
    <meta name="vs_defaultClientScript" content="JavaScript">
    <meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">
  </HEAD>
  <body MS_POSITIONING="GridLayout">
    <form id="Form1" method="post" runat="server">
      <asp:DataList id="DataList1" style="Z-INDEX: 101; LEFT: 256px; POSITION: absolute; TOP: 144px"
        runat="server">
        <ItemTemplate>
          <h1><%# ((System.Xml.XmlNode)Container.DataItem).Attributes["iPackageID"].Value %></h1>
        </ItemTemplate>
        </asp:DataList>
    </form>
  </body>
</HTML>

The real work here is done in the ItemTemplate, specifically where we use the special binding syntax (<%# ... %>) for ASP.NET.  The Container.DataItem property is pointing at the current thing in the IEnumerable object being bound to.  XmlNodeList is a collection of XmlNode references, so Container.DataItem will point to a single XmlNode object reference.  So, we cast Container.DataItem to an XmlNode type, after which we can access the DOM methods of the XmlNode object.  In this example, we use the Attributes collection.

  • Great tip!!
  • cool! Is anyone working on an advanced ASP.NET tips & tricks?
  • I am working on a series of articles for the ASPAlliance that will explain a lot of the innards of ASP.NET. What types of information would you like to see?

    You might want to check out the ASP.NET Developer's Cookbook by Steven Smith, Rob Howard, and assorted folks from the ASPAlliance.

    http://www.amazon.com/exec/obidos/tg/detail/-/0672325241

  • In the above example how to access the iModuleID ?
  • Since you are positioned on an XmlNode named "Packages", you could use an XPath statement to retrieve it.

    <%# ((System.Xml.XmlNode)Container.DataItem.SelectSingleNode("Modules/@iModuleID").Value %>
  • How would you do this part in vb.net, specifically for an element?

    <%# ((System.Xml.XmlNode)Container.DataItem).Attributes["iPackageID"].Value %>

  • Nevermind, got it:

    <%#(Ctype(Container.DataItem, System.Xml.XmlNode))("ElementName").InnerText %>
  • What about DropDownList and other controls derived from ListControl? Could you bind IEnumerable data source to them?
  • I get this
    'XmlNode' is a type in 'Xml' and cannot be used as an expression

    help
  • You most likely forgot to access a property of the node, like ".Value" or ".Name". The code posted above, verbatim, works.
  • I made a mistake too embarrasing to admit here, in public. It would be a grave dishonor to my family name.

    Well, ok, I forgot to specify c# as the page language. apparently the default is vb.
  • In this example, what is the best way to retrieve childnodes of the path:

    doc.SelectNodes("Projects/Packages");

    would you call methods of XmlNode within the aspx, or call selectNodes(...) with a path to the childnodes, and then bind it to another DataList?

  • I would use the latter, for simplicity. I think it would be possible to construct an elaborate binding expression for a child binding, but I think the complexity would be difficult to effectively maintain.
  • Great article... just what I was looking for! However, if you're using XMLElements rather than attributes for the Modules data, you may find the following useful:

    <%# ((System.Xml.XmlNode)Container.DataItem)["iModuleID"].InnerText %>

    <%# ((System.Xml.XmlNode)Container.DataItem)["vModuleName"].InnerText %>

    Which will work with the following XML:

    <Projects iProjectID ="13" vProjectName ="Plumber's Project" >
    <Packages iPackageID ="36" vPackageName ="Bowser" >
    <Modules>
    <iModuleID>76</iModuleID>
    <vModuleName>Bob-omb Module</vModuleName>
    </Modules>
    </Packages>
    <Packages iPackageID ="40" vPackageName ="Princess" >
    <Modules>
    <iModuleID></iModuleID>
    <vModuleName></vModuleName>
    </Modules>
    </Packages>
    </Projects>

Page 1 of 2 (30 items) 12
Leave a Comment
  • Please add 1 and 7 and type the answer here:
  • Post
Translate This Page
Search
Archive
Archives