In my last post, I gave an example of retrieving XML data from an SQL Server relation. So how can we now present that data? As the saying goes, there is more than one way to skin a cat. I’m going to go through two solutions that I came up with off the top of my head.
The primary key of each row correlates to a fragment of XML data. But such a fragment is not very human readable, unless you remove the XML tags. One very easy way of presenting this would be through using an embedded GridView:
note: I did not put any time into presentation. I just wanted to concentrate on functionality here.

To achieve this, I cheated a little bit by binding the XML field to a Label, which I included in the same template column as the embedded GridView (see line 7 for the embedded GridView and line 16 for the Label):
Then, in the code behind, I created a DataSet by reading the Text property of the Label into a StringReader. I was able to use that to read in the XML to the DataSet. There are a couple of other small nuances I included which you will see in the following code:
protected void GridViewEmployees_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
Label LabelREP = e.Row.FindControl("LabelREP") as Label;
DataSet dsXml = new DataSet("REP");
String firstLine = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>";
String frag = Server.HtmlDecode(firstLine + LabelREP.Text);
StringReader readString = new StringReader(frag);
dsXml.ReadXml(readString);
GridView GridViewEmployeeDetails = e.Row.FindControl("GridViewEmployeeDetails") as GridView;
GridViewEmployeeDetails.DataSource = dsXml;
GridViewEmployeeDetails.DataBind();
LabelREP.Text = string.Empty;
}
}
It is possible to achieve the same thing without using a Label, but I’ll leave that for another day as it is a bit more complicated.
The other approach that I thought of is more interesting than that first approach. With this approach, I am going to use the LINQ object XElement to work with the XML. And then I will dynamically (and manually) build the contents of the “Sales REP” column using a Placeholder, which will replace the embedded GridView that I used in the first example.
So, looking at the template field in the GridView. I now have a placeholder, along with the Label which will initially store the contents of the Xml field:
<asp:TemplateField HeaderText="Sales Rep">
<ItemTemplate>
<asp:PlaceHolder ID="PlaceHolderXml" runat="server"></asp:PlaceHolder>
<asp:Label ID="LabelREP" runat="server" Text='<%# ((DataRowView)Container.DataItem)["SalesRep"] %>' />
</ItemTemplate>
</asp:TemplateField>
I have included the whole code for the RowDataBound event handler. However, a lot of that code is guarding against situations like when the XML message is empty. The core part to see what I am doing is from line 43. That shows how I parsed the XML fragment into an XElement object and then traversed each of its child nodes to extract the relevant information for display:
protected void GridViewEmployees_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
// Populate PlaceHolder control dynamically with data from the relevent Xml msg.
PlaceHolder xmlOutput = e.Row.FindControl("PlaceHolderXml") as PlaceHolder;
Label LabelREP = e.Row.FindControl("LabelREP") as Label;
string xmlMsg = LabelREP.Text;
switch (xmlMsg == string.Empty)
{
// if there is no Xml 'Details' field, display that to page;
case true:
{
Literal promptText = new Literal();
promptText.Mode = LiteralMode.PassThrough;
promptText.Text = "<div class=\"msgContent\" ><div class=\"msgContentHeader\">Sales Rep Details</div> " +
"<p> There was no XML field for this blocked item. </p></div><br />";
xmlOutput.Controls.Add(promptText);
break;
}
default:
{
// Check for empty msg elements
switch (xmlMsg.CompareTo("<messages />") == 0)
{
case true:
{
// If the msg is empty, write that out to the Page.
Literal promptText = new Literal();
promptText.Mode = LiteralMode.PassThrough;
promptText.Text = "<div class=\"msgContent\" ><div class=\"msgContentHeader\">Sales Rep Details</div> " +
"<p> The xml fragment was an empty element. </p></div><br />";
xmlOutput.Controls.Add(promptText);
break;
}
default:
{
// Get the xml fragment and parse it into an XElement variable
XElement dbXmlField = XElement.Parse(xmlMsg);
// Popluate the Placeholder control with content.
Literal wrapperDiv = new Literal();
wrapperDiv.Mode = LiteralMode.PassThrough;
wrapperDiv.Text = "<div class=\"msgContent\" ><div class=\"msgContentHeader\">Sales Rep Details</div>";
xmlOutput.Controls.Add(wrapperDiv);
foreach (XElement el in dbXmlField.Descendants())
{
// Traverse the descendant nodes, and add them to the
// placeholder text where the node itself has only 1 child
// node i.e. the text node containing the data that we are
// interested in.
if (el.DescendantNodes().Count() > 1)
continue;
Literal promptText = new Literal();
promptText.Mode = LiteralMode.PassThrough;
promptText.Text = string.Concat(string.Concat("<div class=\"msgLabel\">", el.Name, ": "), "</div>");
xmlOutput.Controls.Add(promptText);
Literal valueText = new Literal();
valueText.Mode = LiteralMode.PassThrough;
valueText.Text = string.Concat("<div class=\"msgValue\">", el.Value, "</div>");
xmlOutput.Controls.Add(valueText);
}
// Close out the content being built in the Placeholder.
Literal wrapperDivClose = new Literal();
wrapperDivClose.Mode = LiteralMode.PassThrough;
wrapperDivClose.Text = "</div><br />";
xmlOutput.Controls.Add(wrapperDivClose);
break;
}
}
break;
}
}
LabelREP.Visible = false;
}
}
And the fruit of my efforts looks something like the following (showing two rows from the result set):
