Creating Sharepoint/MOSS sitemap

mosssharepointsitemap

I'm trying to create a sitemap for my MOSS publishing site, i've got two approaches but seem to be stuck with both.

My first approach is to use the PortalSiteMapProvider, which is already created and nicely cached…

PublishingWeb rootWeb = PublishingWeb.GetPublishingWeb(SPContext.Current.Site.RootWeb);

//Get the URL of the default page in the web
string defaultPageUrl = rootWeb.DefaultPage.ServerRelativeUrl;

PortalListItemSiteMapNode webNode = (PortalListItemSiteMapNode)PortalSiteMapProvider.CurrentNavSiteMapProviderNoEncode.FindSiteMapNode(defaultPageUrl);

HttpContext.Current.Response.Output.WriteLine("Top Level: " + webNode.Title.ToString() + "<br />");

//iterate through each one of the pages and subsites
foreach (SiteMapNode smnTopLevelItem in webNode.ParentNode.ChildNodes)
{

    HttpContext.Current.Response.Output.WriteLine(smnTopLevelItem.Title.ToString() + "<br />");

    //if the current sitemap has children, create a submenu for it
    if (smnTopLevelItem.HasChildNodes)
    {
        foreach (SiteMapNode smnChildItem in smnTopLevelItem.ChildNodes)
        {
         HttpContext.Current.Response.Output.WriteLine(smnChildItem.Title.ToString() + "<br />");
        }
    }
}

HttpContext.Current.Response.End();

but this seems to return everything in the site collection (e.g. lists, surverys). I only want to show the Sharepoint webs.

My other approach was to use this piece of code..

SPSite siteCollection = new SPSite("http://example.org");
SPWebCollection sites = siteCollection.AllWebs;
foreach (SPWeb site in sites)
{
    Console.WriteLine(site.Title.ToString() + " " + site.ServerRelativeUrl.ToString());
}

Which is perfect, apart from the problem of returning all the webs in a flat list.

Ideally I want to be able to add indentation to show child webs.

Best Answer

Generally it's a bad idea to use the object model for recursion. It's extremely slow and resource-intensive to do this. PortalSiteMapProvider is pre-cached for you and can tear through an entire site structure in milliseconds.

Regarding your question about SPSite.AllWebs, that property does return a flat list of all webs. That's what it's for. If you want a list of only the immediate child webs, use the SPSite.RootWeb.Webs property. Recurse over each SPWeb in the .Webs property, and call their .Webs property in turn to get a tree-view.

Also, when dealing with the object model, make sure to DISPOSE EVERY WEB AND SITE. This will cause epic bad problems if you don't. This includes disposing every web in the .Webs collection, even if you haven't touched it.

Edit:

To get the PortalSiteMapProvider to return only webs, set its IncludePages property to false.