tags:

views:

40

answers:

3

I am reading XML using xmlreader, and then binding the xml to a Repeater

Here's the code behind:

            XmlReaderSettings settings = new XmlReaderSettings();
        settings.ProhibitDtd = false;

        XmlReader xmlData = XmlReader.Create(webClient.OpenRead(requestUrl), settings);

        try
        {
            xmlData.ReadToFollowing("SearchResults");
            Label1.Text = xmlData.GetAttribute("TotalCount");
            int numberResults = Convert.ToInt32(xmlData.GetAttribute("TotalCount"));
            if (numberResults > 0)
            {
                DataSet ds = new DataSet();
                ds.ReadXml(xmlData);
                Repeater1.DataSource = ds.Tables[1];
                Repeater1.DataBind();
            }
            else
            {
                Repeater1.DataSource = null;
                Repeater1.DataBind();
            }
        }

Here's the repeater

        <asp:Repeater ID="Repeater1" runat="server">
    <HeaderTemplate><b>Results</b><br /><br /></HeaderTemplate>
    <ItemTemplate>
   <a href="<%#DataBinder.Eval(Container.DataItem, "Url")%>">
    <%#DataBinder.Eval(Container.DataItem, "Title")%></a><br />
    </ItemTemplate>
    </asp:Repeater>

And the xml looks like:

  <SearchResults PageSize="1" PageIndex="0" TotalCount="155">
<SearchResult>
  <ContentId>2458</ContentId>
  <Title>Component description</Title>
  <Url>http://whatever/19/p/1537/2458.aspx&lt;/Url&gt;
  <Date>2009-06-10T09:34:00+01:00</Date>
  <ContentType>forum</ContentType>
  <Tags>
    <Tag>Component</Tag>
  </Tags>
  <Users>
    <User>
      <Id>2533</Id>
      <DisplayName>Haubent</DisplayName>
      <Username>Haubent</Username>
    </User>
  </Users>
  <IndexedAt>2010-07-29T15:40:52.414+01:00</IndexedAt>
</SearchResult>

So far so good.

But - I want to be able to show the contents of the DisplayName node in my repeater item template.

I tried

<%#DataBinder.Eval(Container.DataItem, "DisplayName")%>

and

<%#DataBinder.Eval(Container.DataItem, "Users.User.DisplayName")%>

but I get an error:

System.Web.HttpException: DataBinding: 'System.Data.DataRowView' does not contain a property with the name 'Users'.

How to get at the DisplayName?

+1  A: 

If you inspect (by setting a breakpoint at ds.ReadXml(xmlData);) the dataset you'll see that the Users and User elements actually ends up as records in their own tables. The records have id columns that enables you to relate the rows back to the containing SearchResult row.

In your sample your are binding Tables[1], which is the SearchResult table, to the repeater. You should rather make a selection into the dataset joining the three tables together. LINQ should prove useful here.

Peter Lillevold
A: 

You can use xml deserialization to helper class, that copies the structure of xml nodes and inside the repeater create another repeater for Users collection like this:

<asp:Repeater runat="server" DataSource='<%# Eval("Users") %>' >...
Jan Remunda
+1  A: 

I think the best (and most natural) way to do this is by using Linq To XML. You can change your try block in this way:

try
{
    xmlData.ReadToFollowing("SearchResults");
    Label1.Text = xmlData.GetAttribute("TotalCount");
    int numberResults = Convert.ToInt32(xmlData.GetAttribute("TotalCount"));
    if (numberResults > 0)
    {
        XDocument xml = XDocument.Parse(xmlData.ReadOuterXml());

        Repeater1.DataSource = xml.Element("SearchResults").Elements("SearchResult");
        Repeater1.DataBind();
    }
    else
    {
        Repeater1.DataSource = null;
        Repeater1.DataBind();
    }
}
catch 
{
    // do some catch
}

passing an XElement collection to de repeater. Then you can declare an OnRepeaterDataBound method similar to this:

protected void Repeater1_OnItemDataBound(object sender, RepeaterItemEventArgs e) 
{
    if ((e.Item.ItemType == ListItemType.Item) || ((e.Item.ItemType == ListItemType.AlternatingItem))) 
    {
        XElement User = ((XElement)e.Item.DataItem).Element("Users").Element("User");

        HyperLink hlUrl = ((HyperLink)e.Item.FindControl("hlUrl"));

        hlUrl.NavigateUrl = ((XElement)e.Item.DataItem).Element("Url").Value;
        hlUrl.Text = User.Element("DisplayName").Value;
    }
}

Having the repeater as:

<asp:Repeater ID="Repeater1" runat="server" OnItemDataBound="Repeater1_OnItemDataBound">
    <HeaderTemplate>
        <b>Results</b><br />
        <br />
    </HeaderTemplate>
    <ItemTemplate>
        <asp:HyperLink ID="hlUrl" runat="server" />
    </ItemTemplate>
</asp:Repeater>

On the Repeater1_OnItemDataBound you will be able to parse your xml in the way you want.

tanathos
Thanks for this code. I have implemented it this way and it works perfectly and gives me much more flexibility than before.
Farthest Shore
You're welcome!
tanathos