I also like to create unordered lists. It lets the designer be flexible with the menus. They can use their own js+css solution to create drop down menus or style it nicely for static menus. The same html can easily become left hand, across the top, drop down, or even a full site map with css changes.
To that note, I like to store the site map data in a hierarchal data structure and use a recursive lambda to generate it. For an example see this small console app below with its output.
output html
<li><a href="/">First</a><li><a href="/firstsub.aspx">FirstSub</a></li><li><a hr
ef="/secondsub.aspx">SecondSub</a></li></li><li><a href="/second.aspx">Second</a
></li>
the source c#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SiteMapDemo
{
class MenuItem
{
public Guid ID {get; set;}
public Guid? ParentID{get;set;}
public string Name { get; set; }
public string Path { get; set; }
public int Rank { get; set; }
}
class Program
{
static void Main(string[] args)
{
List<MenuItem> menu = new List<MenuItem>(new[]{
new MenuItem{ID = Guid.NewGuid(), Name = "First", ParentID=null, Path="/", Rank=0},
new MenuItem{ID = Guid.NewGuid(), Name = "Second", ParentID=null, Path="/second.aspx",Rank=1},
});
menu.AddRange(new[] {
new MenuItem{ID = Guid.NewGuid(), Name = "FirstSub", ParentID=menu[0].ID, Path="/firstsub.aspx",Rank=0},
new MenuItem{ID = Guid.NewGuid(), Name = "SecondSub", ParentID=menu[0].ID, Path="/secondsub.aspx",Rank=1},
});
Func<List<MenuItem>, Guid?, string> renderMenu = null;
renderMenu = (menus, Parent) =>
{
var sub = menus.Where(m => m.ParentID == Parent).OrderBy(s=>s.Rank).ToList();
if (sub.Count > 0)
{
StringBuilder sb = new StringBuilder();
sub.ForEach(s => { sb.Append(String.Format("<li><a href=\"{0}\">{1}</a>{2}</li>", s.Path, s.Name, renderMenu(menus, s.ID))); });
return sb.ToString();
}
return "";
};
Console.Write(renderMenu(menu, null));
Console.ReadLine();
}
}
}