I would use LINQ to SQL(mydatasource assumed SQL) then LINQ to XML then XSLT to get the exact XML you are looking for.
Here is an example:
My XML
<Promotions>
<Promotion>
<Category>Arts & Entertainment</Category>
<Client>Client 1</Client>
<ID>2</ID>
<Title>Get your Free 2</Title>
</Promotion>
<Promotion>
<Category>Community & Neighborhood</Category>
<Client>Client1</Client>
<ID>4</ID>
<Title>Get your Free 4</Title>
</Promotion>
<Promotion>
<Category>Community & Neighborhood</Category>
<Client>Client 1</Client>
<ID>5</ID>
<Title>Get your Free 5</Title>
</Promotion>
<Promotion>
<Category>Community & Neighborhood</Category>
<Client>Client 2</Client>
<ID>1</ID>
<Title>Get your Free 1</Title>
</Promotion>
<Promotion>
<Category>Education</Category>
<Client>Client 3</Client>
<ID>3</ID>
<Title>Get Your Free 3</Title>
</Promotion>
<Promotion>
<Category>Home & Garden</Category>
<Client>Client 4</Client>
<ID>6</ID>
<Title>Get your Free 6</Title>
</Promotion>
</Promotions>
My code:
PromotionsDataContext db = new PromotionsDataContext();
//load sql into XML for tree view js control
XElement Categories =
new XElement("Promotions",
from b in db.Promotion_GetPromotions()
select new XElement("Promotion",
new XElement("Category", b.CategoryName),
new XElement("Client", b.ClientName),
new XElement("ID", b.ID),
new XElement("Title", b.Title)));
XDocument mydoc = new XDocument();
mydoc.Add(Categories);
try
{
// Load the style sheet.
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(@"C:\TransList.xslt");
// Execute the transform and output the results to a writer.
StringWriter sw = new StringWriter();
//XsltSettings mysettings = new XsltSettings();
XmlWriterSettings mysettings = new XmlWriterSettings();
xslt.Transform(mydoc.CreateReader(), null, sw);
My XSLT file:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:asp="http://schemas.microsoft.com/ASPNET/20">
<xsl:output method="html" indent="yes" />
<xsl:key name="categories" match="Category" use="." />
<xsl:key name="client" match="Client" use="." />
<xsl:key name="title" match="Title" use="." />
<xsl:template match="/">
<ul id="red" class="treeview-red">
<xsl:for-each select="/Promotions/Promotion/Category[
generate-id(.) = generate-id(key('categories', .)[1])
]">
<li>
<span>
<xsl:value-of select="."/>
<!--Category-->
</span>
<ul>
<xsl:call-template name="category-client">
<xsl:with-param name="category" select="."/>
<!--Client-->
</xsl:call-template>
</ul>
</li>
</xsl:for-each>
</ul>
</xsl:template>
<xsl:template name="category-client">
<xsl:param name="category" />
<xsl:for-each select="/Promotions/Promotion[Category=$category]/Client[
generate-id(.) = generate-id(key('client', .)[1])
]">
<li>
<span>
<xsl:value-of select="."/>
</span>
<ul>
<xsl:call-template name="category-client-title">
<xsl:with-param name="category" select="$category"/>
<!--Title-->
<xsl:with-param name="client" select="."/>
</xsl:call-template>
</ul>
</li>
</xsl:for-each>
</xsl:template>
<xsl:template name="category-client-title">
<xsl:param name="category" />
<xsl:param name="client" />
<xsl:for-each select="/Promotions/Promotion[Category=$category]/Title[
generate-id(.) = generate-id(key('title', .)[1])
]">
<li>
<span>
<asp:LinkButton ID ="LinkButton{../ID}" runat="server" OnClick="LinkClicked" Text="{.}">
</asp:LinkButton>
</span>
</li>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Here are some things I found when working with XSLT in C#:
http://stackoverflow.com/questions/2181458/what-am-i-doing-wrong-here-having-issues-with-xslt-using-c
http://stackoverflow.com/questions/2281447/need-help-with-xslt
http://stackoverflow.com/questions/2280445/xslt-renders-gt-and-lt-for-how-to-do-i-get-around-this