You can get a tree like structure, combining LINQ and recursion with delegates. In this example I use a XML structure like this:
<Competitions>
<Competition ID="1" />
<Competition ID="2" ParentCompetitionID="1" />
<Competition ID="3" ParentCompetitionID="1" />
<Competition ID="4" />
</Competitions>
So to store node data in code and facilitate navigation, create a class like this:
class Competition
{
public int CompetitionID { get; set; }
public IEnumerable<Competition> Childs { get; set; }
}
Now using Linq to XML you load the xml file into an XDocument. After that declare a delegate that iterates over all the xml elements inside the document selecting nodes that have an id mathing the delegate's id paremeter. When selecting each node, it calls to the delegate again, passing the id of the parent node to look for. It first starts with the id parameter set to null, so, selecting firts the root nodes:
var doc = XDocument.Load("tree.xml");
//Declare the delegate for using it recursively
Func<int?, IEnumerable<Competition>> selectCompetitions = null;
selectCompetitions = (int? id) =>
{
return doc.Elements("Competitions").Elements().Where(c =>
{
//If id is null return only root nodes (without ParentCompetitionID attribute)
if (id == null)
return c.Attribute("ParentCompetitionID") == null;
else
//If id has value, look for nodes with that parent id
return c.Attribute("ParentCompetitionID") != null &&
c.Attribute("ParentCompetitionID").Value == id.Value.ToString();
}).Select(x => new Competition()
{
CompetitionID = Convert.ToInt32(x.Attribute("ID").Value),
//Always look for childs with this node id, call again to this
//delegate with the corresponding ID
Childs = selectCompetitions(Convert.ToInt32(x.Attribute("ID").Value))
});
};
var competitions = selectCompetitions(null);
To test it you can do a simply recurring method that prints the tree to the console:
private static void Write(IEnumerable<Competition> competitions, int indent)
{
foreach (var c in competitions)
{
string line = String.Empty;
for (int i = 0; i < indent; i++)
{
line += "\t";
}
line += "CompetitionID = " + c.CompetitionID.ToString();
Console.WriteLine(line);
if (c.Childs != null && c.Childs.Count() > 0)
{
int id = indent + 1;
Write(c.Childs, id);
}
}
}
Hope it helps!