Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

How to correctly use sitemap for top/left menus

0.00/5 (No votes)
6 Nov 2013 1  
Know about sitemap, multiple sitemaps in a web.config and create navigation menus using sitemap in asp.net

Introduction

With this article i am trying to provide some guidelines on how to correctly use sitemaps to create menus. We will be covering following points in this article

  1. What are sitemaps?
  2. Why sitemaps are useful ?
  3. Sitemap in asp.net
  4. Using more than one sitemap
  5. Using Sitemap to create Menus
  6. Creating Left Menu using the child nodes of sitemap 

What are sitemaps ?  

Sitemap is basically a structure that tells about a hierarchy. Imagine your grand dad. He has two children. And there children have two more out of which you are one. So if some  one draw this simply on a paper joining every person in order as i mentioned, you will basically form a family tree. This representation we basically call as a sitemap. When it comes to websites, a sitemap basically explains the hierarchy in which the pages are placed in the website. For example say homepage have child pages as "about  us","career", "contact us". Further "career" have child pages as "current openings", "apply now" etc. Now who ever is interested in getting this information from a website in one go, will first and foremost try to find the sitemap file in your web solution/site/
XML is a known format of representing any sitemap for a website. So in asp.net also, we use a xml file, for simplicity provided with extension ".sitemap" to create a sitemap 

Why sitemaps are useful ?  

As i explained that anyone who is interested in knowing the page hierarchy of the website will look for this file. Some of the well known people like google, bing or any other search engines that tries to find out about your site, will look for it. So having this file ready is actually good thing for getting your site listed on the search engines. How to do that, is not covered here in this topic. But when as developer your are asked for a sitemap, this is what exactly you have to provide them, though for this purpose the structure is bit different with some different keywords. Ask a SEO expert.
Coming to the main agenda of this article, we can create dynamic menus that will help with navigation through out the site, using a simple sitemap files. For example you normally see a top menu in most of the sites for navigation. Now if we play smart, we can also create submenus using the same sitemap file or menus that are not at all relevent to the page structure but rather action links under particular scenario. Say for example, when a user is logged into the system, we want to show in left menu the number of actions he/she can perform. Lets get started to see how we can actually achieve this use this simple xml file.  

Sitemap in asp.net

 To create your first sitemap, just go to your project-> add new item-> site map.  This will default be named as "web.sitemap". This is how it looks : 

<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
    <siteMapNode url="" title=""  description="">
        <siteMapNode url="" title=""  description="" />
        <siteMapNode url="" title=""  description="" />
    </siteMapNode>
</siteMap>    

 Now if you see the start of this file, it is clearly understood that we are creating nothing but a xml file. Now the first sitemapnode you see is called the root sitemapnode and  inside it we have the child nodes. Also further i will call the very first siteMap as base node. Its just my naming convention so dont fight over it Smile | :) . Now lets see a code block that is bit senseful

<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
    <siteMapNode url="index.aspx" title="Home"  description="Home">
        <siteMapNode url="Services.aspx" title="Services"  description="">
			<siteMapNode url="webdesign.aspx" title="Web Designs"  description="" />
			<siteMapNode url="websitedevelopment.aspx" title="Website Development"  description=""/>
			<siteMapNode url="cmscustomization.aspx" title="CMS Customization"  description="" />
			<siteMapNode url="softwaredevelopment.aspx" title="Software Development"  description="" />
			<siteMapNode url="internetmarketing.aspx" title="Internet Marketing"  description="" />
			<siteMapNode url="mobiledevelopment.aspx" title="Mobile Development"  description="" />
			<siteMapNode url="hostingsolutions.aspx" title="Hosting Solutions"  description="" />
	</siteMapNode>
        <siteMapNode url="products.aspx" title="Products"  description="" >
			<siteMapNode url="tagxtor.aspx" title="HTML Metatag Extractor"  description="" />
			<siteMapNode url="ams.aspx" title="Apartment Management System"  description="" />
			<siteMapNode url="cgnp.aspx" title="Closed Group Network Portal"  description="" />
			<siteMapNode url="ribbon.aspx" title="Retail Management System"  description="" />
	</siteMapNode>
	<siteMapNode url="company.aspx" title="Company"  description="" >
			<siteMapNode url="aboutus.aspx" title="About Us"  description="" />
			<siteMapNode url="team.aspx" title="Our Team"  description="" />
			<siteMapNode url="career.aspx" title="Work With Us"  description="" />
			<siteMapNode url="contactus.aspx" title="Contact Us"  description="" />
	</siteMapNode>
    </siteMapNode>
</siteMap>  

The above sitemap is a part of my companies website. Now you see at root you have the home page as home.aspx and its immediate child nodes as services.aspx, products.aspx and company.aspx. Each child node have several children of there own.
 

Using Sitemap to create Menu

Now lets try to use the above sitemap to create a simple breadcrumb and our first menu.

Breadcrumb

 

Its very simple. Just drag the SiteMapPath control from the toolbox to the place where you want to see it. Just run the solution. You will see it will automatically start displaying the values from the web.sitemap
file.

 <div class="breadcrumb">
     <asp:SiteMapPath ID="SiteMapPath1" runat="server" PathSeparator=" \ "></asp:SiteMapPath>
 </div>

Yes if you do not define the datasource for any control, it takes up the default web.sitemap file and  automatically binds to it. Explore different pages and see how this control is changing values everywhere. Now rather having SiteMapPath control on every page, i suggest you use a masterpage and use this control just once on it. The magic will work here also. What this does is, it searches the page url from the start of the sitemap file and once the url is found, it displays the flow till the found node in the file. One obvious thing here is if the sitemap hierarchy is incorrect , it will show the wrong information in the breadcrumb. It does not test for the actual folder hierarchy of your solution rather the logical hierarchy as mentioned by you. So you have to be cautious over here. Also very important that you do not write same URL twice at different nodes in same sitemap file. Even the "#" is not allowed twice. This will result in a runtime error.

Top Menu 

For creating a top menu i find repeater control as best suited. Repeater control basically repeats a template. Lets see the following code 

<asp:Repeater runat="server" ID="topmenucontainer" DataSourceID="SiteMapDataSource1">
<HeaderTemplate><ul class="nav sf-menu sf-js-enabled"><li class="li-first"><a href='<%= this.Page.ResolveUrl("default.aspx")%>'><img src="../img/home.png" alt="" class="hidden-phone"><span class="visible-phone">Home</span></a></li></HeaderTemplate>
    <ItemTemplate>
        <li >
            <asp:HyperLink ID="HyperLink1" runat="server" NavigateUrl='<%# Eval("Url") %>'><%# Eval("Title") %></asp:HyperLink>
 
            <asp:Repeater ID="Repeater1" runat="server" DataSource='<%# ((SiteMapNode)Container.DataItem).ChildNodes  %>'>
                <HeaderTemplate>
                    <ul>
                </HeaderTemplate>
                
                <ItemTemplate>
                    <li>
                        <asp:HyperLink ID="HyperLink2" runat="server" NavigateUrl='<%# Eval("Url") %>'><%# Eval("Title") %></asp:HyperLink>
                    </li>
                </ItemTemplate>
                
                <FooterTemplate>
                    </ul>
                </FooterTemplate>
            </asp:Repeater>
        </li>
    </ItemTemplate>
    <FooterTemplate></ul></FooterTemplate>
</asp:Repeater>
<asp:SiteMapDataSource ID="SiteMapDataSource1" runat="server" ShowStartingNode="false"  /> 

We have a simple UL LI structure that is capable enough to render our sitemap. It is a nested repeater. See how i have used URL and Title from the sitemap. Also the nested repeater is bounded using the child nodes. Feel free to use this particular template for any of your project as dependency is on the sitemap structure which you will bind. Notice that i have escaped the base node(<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >) by using ShowStartingNode="false".
Once you run this code you will see that the top menu renders exactly as the sitemap.  I have used superfish.js/css to achieve on hover submenu visibility. You may explore on Google about how to use it.

Using more than one sitemap

 You can't provide the sitemap file name to the data source directly. So question is if i am creating a dynamic website i will need different menus in different scenarios. So i need to create multiple sitemaps. To achieve this add as many sitemaps you want but add a corresponding name in web.config file under the <system.web> section. Following example shows how I have added  three sitemaps in my config file. 

 <siteMap defaultProvider="topProvider">
      <providers>
        <clear />
        <add name="topProvider" type="System.Web.XmlSiteMapProvider" siteMapFile="web.sitemap" />
        <add name="sideProviderAdmin" type="System.Web.XmlSiteMapProvider" siteMapFile="leftmenuAdmin.sitemap" />
        <add name="sideProviderCustomer" type="System.Web.XmlSiteMapProvider" siteMapFile="leftmenuCustomer.sitemap" />
      </providers>
    </siteMap>

Two things to observe here. First is "defaultProvider". As the name suggest this sitemap will be binded as default sitemap if the datasource is not specified for the control like we did in breadcrumb example. Second, in provider section we provide the names for all the sitemaps, and this name only we will use when it will come to binding datasource.
Next go to your control and provide a datasource, use SiteMapProvider property to bind to the name we mentioned above.

<asp:SiteMapDataSource ID="SiteMapDataSource1" runat="server" ShowStartingNode="false" SiteMapProvider="topProvider" />

Now think about dynamic scenario where my top menu or left menu needs to be changed basis of a page or the user type after  login. Lets see it below.

 Creating Left Menu using the child nodes of sitemap

Coming to the last part of this article, the general confusions you will have is that what if i need a menu where only child nodes are required. Say when you are visiting a parent node page you need to display all parent pages. Once you are inside any child node, you need to display all its sibling nodes. To achieve this you can scan the sitemap file for a particular node and once found you can use its parent node to show only its child.

Say for general public  we use web.sitemap, for customer we use leftmenuCustomer.sitemap and for admin we use leftmenuAdmin.sitemap. What I want to achieve is, for my web.sitemap file, whenever a user is at a parent page I am displaying all the parent pages. When a child page is visited i am interested in showing all the sibling child node of its parent. And finally for the logged in view for admin and customer, bind their own separate sitemap files. Following code does the magic in this scenario

Customer = Session["Customer"] as CustomerMain;
Administrator = Session["Admin"] as Admin;
 
if (Customer != null || Administrator != null)
{
    if (Customer != null)
        SiteMapDataSource1.SiteMapProvider = "sideProviderCustomer";
    else
        SiteMapDataSource1.SiteMapProvider = "sideProviderAdmin";
}
else
{
    SiteMapDataSource1.SiteMapProvider = "topProvider";
 
    //Find the node in web.sitemap file that corresponds to current page request
    SiteMapNode node = SiteMapDataSource1.Provider.FindSiteMapNodeFromKey(Page.Request.Path);
 
    //if the found node is a child node, set the StartingNodeOffset to 1 in order to bind menu from 1st node and not the node 0 i.e. parent
    if (node != null && !node.HasChildNodes && node.RootNode != node.ParentNode)
        SiteMapDataSource1.StartingNodeOffset = 1;
}
 

The left menu designer code is shown below :

<asp:SiteMapDataSource ID="SiteMapDataSource1" runat="server" ShowStartingNode="false" StartingNodeOffset="0"  />
<asp:Repeater runat="server" ID="sidemenu" DataSourceID="SiteMapDataSource1">
<HeaderTemplate><ul class="list-number"></HeaderTemplate>
    <ItemTemplate>
              <li><span>&nbsp;</span><div>
                <asp:HyperLink ID="HyperLink2" runat="server" NavigateUrl='<%# Eval("Url") %>'><%# Eval("Title") %></asp:HyperLink></div>
            </li>
    </ItemTemplate>
    <FooterTemplate></ul></FooterTemplate>
</asp:Repeater>
 

 Please note that if the control used to display sitemap is capable of reading only the 1st level nodes, it will bind only the first level nodes. That is the reason for topmenu I have used nested repeater to display the second level of nodes. 

StartingNodeOffset basically tells the start point offset to be taken from the sitemap. Say we are at a child page. By default the sitemap will show all the parent nodes. By setting it to 1, it looks out for offset value 1 starting from the current page. Say if we are at "webdesign.aspx" page, setting the offset to 1 looks in upward direction from this node,finds "services.aspx" page node and start displaying all nodes under it.
I hope this makes the application clear. To take it to next level i usually create a top menu and left menu usercontrol and place all the conditions in its code-behind. This way i am not bothered about multiple
masterpages and hence multiple times same type of coding. 

 If you get hold of the above concepts, navigations/menus in your website will become an easy task with minimal coding and easy management and changes in future rather tedious ways, too many if else conditions and n numbers of bindings to achieve the same. I am attaching a working solution here. Following things you will find in it:

  • A valid site map structure. Refer to web.sitemap, leftmenuadmin.sitemap and leftmenucustomer.sitemap
  • How to define multiple sitemaps in web.config
  • How to bind multiple sitemaps based on conditions
  • A topmenu using sitemap
  • A left menu, whose binding changes based on few
    conditions. Notice is child pages, the left menu shows all the child
    pages of the parent page only as listed in the topmenu/sitemap.
  • How to put a breadcrumb with sitemap(look just below the top menu)
  • log in to system and bind left menu as per admin or customer 
  • Last and not the least a stable UI solution using twitter bootstrap and responsive CSS. use fresh files from their respective site as this example might contain too many CSS classes that are not required.

 I hope this article will help many people while you plan any dynamic website's navigation controls. Smile | :) 

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here