Link to home
Start Free TrialLog in
Avatar of cat4larry
cat4larry

asked on

Using a Repeater with XML

Im trying to show within a repeater a Resort and within that repeater another repeater to show the resorts inventory.

Im using XmlNodeList to populate the Resort Data.
Now I need to populate the second repeater so within the ItemDataBound I find the control
for the repeater and Im stuck on now trying to take the ResortID from the first repeater and access the inventory to populate the second repeater.  Below is the XML

 <accommodationItem> is for the resort info (First Repeater)
 <availabilityInfo> is for the resort inventory

 <?xml version="1.0" ?>
- <responseEnvelope>
- <responseHeader>
- <statusData>
  <completionCode>0</completionCode>
  <completionMessage>Request Completed Successfully.</completionMessage>
  </statusData>
  </responseHeader>
- <SearchResponse>
- <sessionToken>
  <sessionId>3203300</sessionId>
  </sessionToken>
- <accommodationItem>
  <resortId>0450</resortId>
  <resortName>Resort 1</resortName>
  <nbrOfBedrooms>2</nbrOfBedrooms>
  <nbrOfBathrooms>0.0</nbrOfBathrooms>
  <kitchenType>Full Kitchen</kitchenType>
  <maxOccupancy>8</maxOccupancy>
  <privacyOccupancy>6</privacyOccupancy>
- <availabilityInfo>
- <systemId>
  <inventoryType>1</inventoryType>
  <inventoryId>rNnn6T4Gwjd6r9sj4w+3CXgtWrNbxbMWJzoakGRFDrTEhWAqo2rI4ALOtq+vOkUx</inventoryId>
  </systemId>
  <checkInDate>05/30/2009</checkInDate>
  <checkOutDate>06/06/2009</checkOutDate>
- <unitCost>
  <value>325.00</value>
  <currency>USD</currency>
  </unitCost>
  <unitCount>1</unitCount>
  </availabilityInfo>
- <availabilityInfo>
- <systemId>
  <inventoryType>1</inventoryType>
  <inventoryId>rNnn6T4Gwje0Lt74wo40nXgtWrNbxbMWJzoakGRFDrTEhWAqo2rI4ALOtq+vOkUx</inventoryId>
  </systemId>
  <checkInDate>05/31/2009</checkInDate>
  <checkOutDate>06/07/2009</checkOutDate>
- <unitCost>
  <value>325.00</value>
  <currency>USD</currency>
  </unitCost>
  <unitCount>2</unitCount>
  </availabilityInfo>
  </accommodationItem>


Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
 Dim nodes As XmlNodeList = xmlDocument.SelectNodes("//responseEnvelope/SearchResponse/accommodationItem")
       RepeaterMain.DataSource = nodes
        RepeaterMain.DataBind()
End Sub
 
  Protected Sub RepeaterMain_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.RepeaterItemEventArgs) Handles RepeaterMain.ItemDataBound
  
InventoryRepeater = DirectCast(item.FindControl("InventoryRepeater"), Repeater)
  Dim drv As DataRowView = DirectCast(item.DataItem, DataRowView)
 PlayerRepeater.DataSource = drv.CreateChildView("node-here?") ' HERE IS THE PROBLEM HOW DO I ACCESS THE NODE WITH THE INVENTORY
PlayerRepeater.DataBind()
End Sub

Open in new window

Avatar of tetorvik
tetorvik
Flag of Finland image

If you're binding XmlNodeList to your first repeater then you should cast the item.DataItem to XmlElement and then quering it with XPath to retrieve the data you're intrested for the second repeater: below is the C# sample (I'm more familiar with it), I bet you get the idea. But please tell if you need VB.NET sample as well.
        void Resort_ItemDataBound(object sender, RepeaterItemEventArgs e)
        { 
            XmlElement elem = (XmlElement)e.Item.DataItem; // gets XmlElement bound to this row
            XmlNodeList availabilityInfos = elem.SelectNodes("availabilityInfo"); //Query the child elements for second repeater
            inventory.DataSource = availabilityInfos;
            inventory.DataBind();
        }

Open in new window

Avatar of cat4larry
cat4larry

ASKER

Thanks I actually figured it out with a datatable I will try it your way.  I will reward you the points.  

With the first repeater <accommodationItem>  what is the best way to group it by the <resortId>.
 I only want to show a resort once and then show everything else like <nbrOfBedrooms> and <availabilityInfo> under it.  I have it working in a grid instead of a repeater but im getting a duplicate resort since the XML returns the same resort twice if the <nbrOfBedrooms> and <availabilityInfo> are different.

So here is how it should look
**HEADER*** * In a repeater
ResortID, Resort Name

***GRID***
Number of bedrrooms, Checkindate, Checkout date, Unit Cost

I haven't done XML grouping by myself, I knew it could be done by using XSLT, but I came across a LINQ sample that was really intresting:
http://forums.asp.net/t/1406394.aspx

I've also applied the appreach to your xml structure (see the snippet). I haven't bound the query to Repeater but asp.net forum site has a good example of it.

Thanks for the question!


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml;
using System.Xml.Linq;
 
public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
   
        XDocument xdoc = XDocument.Load(Server.MapPath("~/XMLFile1.xml"));
          var query =
            from accommodationItem in xdoc.Root.Descendants("accommodationItem")
            group accommodationItem by (string)accommodationItem.Element("resortId") into item1
            select new
            {
                resortId = item1.Key,
                groupItems = from gi in item1
                     select new
                     {
                         nbrOfBedrooms = (string)gi.Element("nbrOfBedrooms"),
                         resortId = (string)gi.Element("resortId"),
                         checkIn = (DateTime)gi.Element("availabilityInfo").Element("checkInDate"),
                         checkOut = (DateTime)gi.Element("availabilityInfo").Element("checkOutDate"),
                         cost = (string)gi.Element("availabilityInfo").Element("unitCost").Element("value")
                     }
 
            };
 
        foreach (var item in query)
          {
              Response.Write(string.Format("ResortId: {0}:<br>", item.resortId));
              foreach (var gr in item.groupItems)
              {
                  Response.Write(string.Format("Bedrooms: {0}:<br>", gr.nbrOfBedrooms));
                  Response.Write(string.Format("Check-in: {0}:<br>", gr.checkIn.ToShortDateString()));
                  Response.Write(string.Format("Check-out: {0}:<br>", gr.checkOut.ToShortDateString()));
                  Response.Write(string.Format("Cost: {0}:<br>", gr.cost));
              }
          }
    }
}

Open in new window

tetorvik can you supply that in VB I ran into some issues when trying to convert it?
ASKER CERTIFIED SOLUTION
Avatar of tetorvik
tetorvik
Flag of Finland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I got the same error when I converted it .  In the first part Dim Query I get End of statement expected

For Each item In query, I get item not declared what should item be declared as.

Thanks for your help
What framework version you're using? LINQ is framework 3.5 feature. Also remember to import System.Xml.Linq namespace.
3.5 and I have the System.Xml.Linq namespace.
I really cannot figure out what you're missing. no matter if I create a web site or web application project and add the fragment in page_load event I get it succefully compiling. Are you adding this functionality to an existing project? Does this work if you create a new project for this?
It took some tweaking but one of my developers was able to get it.  

Thanks