As I said in a previous post, here's the code for generating a sitemap. Enjoy.
SiteMapGenerator.cs
using System;
using Snowball.Common;
using System.IO;
namespace Snowball.Web
{
///
/// Generates a sitemap for dotnetnuke.
///
class SiteMapGenerator
{
///
/// Generates a site map for a dotnetnuke 2.1.2 website.
///
[STAThread]
static void Main(string[] args)
{
string portals=Settings.GetSetting("Portals");
string[] portalList=portals.Split(new char[]{','});
string htmlFilename=Settings.GetSetting("HtmlFileName");
string xmlFilename=Settings.GetSetting("XmlFileName");
string googleFilename=Settings.GetSetting("GoogleSiteMapFileName");
for (int i=0;i < portalList.Length;i++)
{
string[] portalData=portalList[i].Split(new char[]{'|'});
int portalId=Convert.ToInt32(portalData[0]);
string baseUrl=portalData[1];
string outputDir=portalData[2];
if (!outputDir.EndsWith(@"\"))
{
outputDir+=@"\";
}
TabList list=TabList.GetTabs(portalId,baseUrl);
using (StreamWriter writer=new StreamWriter(outputDir + xmlFilename))
{
writer.Write(list.ToXml());
}
using (StreamWriter writer=new StreamWriter(outputDir + googleFilename))
{
writer.Write(list.ToGoogleSitemap());
}
using (StreamWriter writer=new StreamWriter(outputDir + htmlFilename))
{
writer.Write(list.ToString());
}
}
}
}
}
Tab.cs
using System;
using System.Data;
using Microsoft.ApplicationBlocks.Data;
using Snowball.Common;
using log4net;
using System.Text;
using System.Collections;
namespace Snowball.Web
{
///
/// Represents a single dotnetnuke tab.
///
internal class Tab
{
private TabList m_childTabs=new TabList();
private bool m_hasChildren=false;
private Uri m_url=null;
private string m_anchor;
private string m_description;
private int m_id=-1;
private int m_parentId=-1;
private int m_tabOrder=-1;
private int m_level=-1;
private bool m_isVisible=false;
private bool m_disabled=false;
private bool m_deleted=false;
private bool m_adminTab=false;
private string m_defaultPage=string.Empty;
private string m_defaultHost="http://www.mysite.com/";
private static DataSet m_rewriterDirectories=null;
private static SortedList m_dirs=null;
private static string m_dnnCs=Settings.GetSetting("DotNetNukeConnectionString");
private static string m_snowballCs=Settings.GetSetting("SnowballConnectionString");
///
/// Default Constructor.
///
public Tab()
{
}
///
/// Allow creation of tab with specified portal id and default host.
///
/// The portal id for this tab.
/// The default host for this tab.
public Tab(int portalId, string defaultHost)
{
if (!defaultHost.EndsWith("/"))
{
defaultHost+="/";
}
m_defaultHost=defaultHost;
m_childTabs.DefaultHost=defaultHost;
m_childTabs.PortalId=portalId;
}
///
/// Allows creation of a specific tab.
///
/// The id of the tab to create.
/// The portal id of the tab.
/// the default host of this tab.
public Tab(int id,int portalId,string defaultHost):this(portalId,defaultHost)
{
LoadTab(id);
}
///
/// Allows for the creation of a tab from a datarow.
///
/// The data row containing the tab data.
/// The portal of this tab.
/// The host of this tab.
public Tab(DataRow row,int portalId,string defaultHost):this(portalId,defaultHost)
{
LoadTab(row);
}
///
/// Gets or sets child tabs of this tab.
///
public TabList ChildTabs
{
get
{
return m_childTabs;
}
set
{
m_childTabs=value;
}
}
///
/// Gets or sets whether or not this tab has children.
///
public bool HasChildren
{
get
{
return m_hasChildren;
}
set
{
m_hasChildren=value;
}
}
///
/// Gets the URI for this tab.
///
public Uri Url
{
get
{
return m_url;
}
}
///
/// Gets the tab description--note that this is the title of the tab.
///
public string Description
{
get
{
return m_description;
}
}
///
/// Gets an anchor (A) tag for html.
///
public string Anchor
{
get
{
return "this.Url.ToString() + "\">" + this.Description + "";
}
}
///
/// Gets the id of this tab.
///
public int Id
{
get
{
return m_id;
}
}
///
/// Gets the parent Id of this tab.
///
public int ParentId
{
get
{
return m_parentId;
}
}
///
/// Gets the Tab Order for this tab.
///
public int TabOrder
{
get
{
return m_tabOrder;
}
}
///
/// Gets this tab's level.
///
public int Level
{
get
{
return m_level;
}
}
///
/// Gets whether or not this tab is visible.
///
public bool Visible
{
get
{
return m_isVisible;
}
}
///
/// Gets whether or not this tab is disabled.
///
public bool Disabled
{
get
{
return m_disabled;
}
}
///
/// Gets whether or not this tab has been deleted.
///
public bool Deleted
{
get
{
return m_deleted;
}
}
///
/// Gets or sets whether this tab is the admin tab or not.
///
public bool AdminTab
{
get
{
return m_adminTab;
}
set
{
m_adminTab=value;
}
}
///
/// Loads a tab from a datarow.
///
/// The row containing the data for this tab.
private void LoadTab(DataRow row)
{
SetValue(row["Title"],ref m_description);
m_url=SetUri((int) row["TabId"]);
m_anchor="" + m_description + "";
SetValue(row["IsDeleted"],ref m_deleted);
SetValue(row["DisableLink"],ref m_disabled);
SetValue(row["HasChildren"],ref m_hasChildren);
SetValue(row["TabId"],ref m_id);
SetValue(row["IsVisible"],ref m_isVisible);
SetValue(row["Level"],ref m_level);
SetValue(row["ParentId"],ref m_parentId);
SetValue(row["TabOrder"],ref m_tabOrder);
}
///
/// Sets a value if the value is not DBNull.Value.
///
/// The value to check for DBNull
/// The ref obejct variable to set if the value is not dbnull.
private void SetValue(object value, ref object variable)
{
if (value != DBNull.Value)
{
variable=value;
}
}
///
/// Sets a value if the value is not DBNull.Value.
///
/// The value to check for DBNull
/// The ref obejct variable to set if the value is not dbnull.
private void SetValue(object value, ref string variable)
{
object result=null;
SetValue(value,ref result);
if (result != null)
{
variable=Convert.ToString(result);
}
}
///
/// Sets a value if the value is not DBNull.Value.
///
/// The value to check for DBNull
/// The ref obejct variable to set if the value is not dbnull.
private void SetValue(object value, ref int variable)
{
object result=null;
SetValue(value,ref result);
if (result != null)
{
variable=Convert.ToInt32(result);
}
}
///
/// Sets a value if the value is not DBNull.Value.
///
/// The value to check for DBNull
/// The ref obejct variable to set if the value is not dbnull.
private void SetValue(object value, ref bool variable)
{
object result=null;
SetValue(value,ref result);
if (result != null)
{
variable=Convert.ToBoolean(result);
}
}
///
/// Loads a tab from an id.
///
/// The int id of the tab to load.
private void LoadTab(int id)
{
m_id=id;
DataSet ds=SqlHelper.ExecuteDataset(m_dnnCs,"GetTab",new object[]{id});
if (ds.Tables[0].Rows.Count > 0)
{
DataRow row=ds.Tables[0].Rows[0];
LoadTab(row);
}
}
///
/// Builds the URI for this tab. Note that we rewrite certain directories to have better names (like signup instead of default.aspx?tabid=32). We want the
/// better names to appear in the site map instead of the more complex, so this function does that mapping.
///
/// The tab id that we're building a url for.
/// A URI containing a reference to this tabs internet location.
private Uri SetUri(int tabId)
{
GetRewriterDirectories();
string url=GetUrl(tabId);
m_url=new Uri(url);
return m_url;
}
///
/// gets the root page for dotnetnuke. Note that we've assumed default.aspx.
///
/// A string containing the default host and the default web page.
private string GetRootPage()
{
if (m_defaultPage==string.Empty)
{
m_defaultPage=m_defaultHost + "default.aspx";
}
return m_defaultPage;
}
///
/// Gets a list of the url rewriter directories that are in use.
///
private void GetRewriterDirectories()
{
if (m_rewriterDirectories==null)
{
m_rewriterDirectories=SqlHelper.ExecuteDataset(m_snowballCs,"spUrlRewriterDirectoriesGetAll",null);
m_dirs=new SortedList();
DataRowCollection rows=m_rewriterDirectories.Tables[0].Rows;
for (int i=0;i < rows.Count;i++)
{
string url=(string) rows[i]["RewriteUrl"];
string[] urlParts=url.Split(new char[]{'?'});
string query=urlParts[1].TrimStart(new char[]{'?'}).ToLower();
string[] queryParts=query.Split(new char[]{'&'});
int tabId=-1;
for (int j=0;j < queryParts.Length;j++)
{
string[] queryItem=queryParts[j].Split(new char[]{'='});
if (queryItem[0]=="tabid")
{
tabId=Convert.ToInt32(queryItem[1]);
break;
}
}
//we take the first one we see.
if (!m_dirs.ContainsKey(tabId))
{
m_dirs.Add(tabId,(string) rows[i]["DirectoryName"]);
}
}
}
}
///
/// Gets a url for a specific tab id.
///
/// The tabid to build.
/// A string containing a url (like default.aspx?tabid=32)
private string GetUrl(int tabId)
{
string url=string.Empty;
if (m_dirs.ContainsKey(tabId))
{
url+=m_defaultHost + (string) m_dirs[tabId] + "/";
}
else
{
url+=GetRootPage() + "?tabId=" + tabId.ToString();
}
return url;
}
}
}
TabList.cs
using System;
using System.Collections;
using Snowball.Common;
using Microsoft.ApplicationBlocks.Data;
using System.Data;
using log4net;
using System.Text;
using System.Xml;
namespace Snowball.Web
{
///
/// A list of tabs in DotNetNuke.
///
internal class TabList : CollectionBase, IList, IEnumerable
{
private int m_portalId=-1;
private string m_defaultHost=string.Empty;
private DataRow m_portalSettings=null;
private string m_xml=string.Empty;
///
/// Default constructor.
///
public TabList()
{
}
///
/// Creates a tab list for the given portal and default host.
///
/// The portal id for this list.
/// The default host for this list.
public TabList(int portalId, string defaultHost)
{
m_portalId=portalId;
m_defaultHost=defaultHost;
LoadPortalSettings();
}
#region IList Members
public Tab this[int index]
{
get
{
return (Tab) List[index];
}
set
{
List[index]=value;
}
}
public void Insert(int index, Tab value)
{
List.Insert(index,value);
}
public void Remove(Tab value)
{
List.Remove(value);
}
public bool Contains(Tab value)
{
return List.Contains(value);
}
public int IndexOf(Tab value)
{
return List.IndexOf(value);
}
public int Add(Tab value)
{
return List.Add(value);
}
///
/// Adds a child given the parent Id of the childs parent.
///
/// The id of the parent.
/// The child tab to add.
public void AddChild(int parentId, Tab child)
{
Tab parent=this.GetById(parentId);
AddChild(parent,child);
}
///
/// Adds a child to the specified parent.
///
/// The parent tab to which a child is to be added.
/// The child tab to add.
public void AddChild(Tab parent, Tab child)
{
if (parent != null && child != null)
{
if (parent.AdminTab)
{
child.AdminTab=true;
}
parent.ChildTabs.Add(child);
}
}
///
/// Returns a list by its id. Note that children must also be search to find the correct tab.
///
/// The id of the tab to get.
/// A tab for the specified Id or null.
public Tab GetById(int tabId)
{
Tab tab=null;
for (int i=0;i < this.Count;i++)
{
if (this[i].Id==tabId)
{
tab=this[i];
break;
}
if (this[i].HasChildren)
{
Tab child=this[i].ChildTabs.GetById(tabId);
if (child != null)
{
tab=child;
break;
}
}
}
return tab;
}
#endregion
///
/// Static method that returns a tablist for the specified portal and host.
///
/// The portal id for which to make a web map.
/// The default host for this webmap.
/// A tablist containing the tabs for the given portal.
public static TabList GetTabs(int portalId, string defaultHost)
{
DataSet ds=SqlHelper.ExecuteDataset(Settings.GetSetting("DotNetNukeConnectionString"),"GetTabs",new object[]{portalId});
TabList list=new TabList(portalId,defaultHost);
DataRowCollection rows=ds.Tables[0].Rows;
for (int i=0;i < rows.Count;i++)
{
Tab tab=new Tab(rows[i],portalId,defaultHost);
if (list.AdminTabId==tab.Id)
{
tab.AdminTab=true;
}
if (tab.ParentId != -1)
{
list.AddChild(tab.ParentId,tab);
}
else
{
list.Add(tab);
}
}
return list;
}
///
/// Gets the root tab Id.
///
public int RootId
{
get
{
LoadPortalSettings();
return (int)m_portalSettings["HomeTabId"];
}
}
///
/// Gets the default host.
///
public string DefaultHost
{
get
{
return m_defaultHost;
}
set
{
m_defaultHost=value;
}
}
///
/// The portal id of this list.
///
public int PortalId
{
get
{
return m_portalId;
}
set
{
m_portalId=value;
}
}
///
/// The admin tab id of this list.
///
public int AdminTabId
{
get
{
LoadPortalSettings();
return (int)m_portalSettings["AdminTabId"];
}
}
///
/// Returns an HTML representation of the site map. Note that this uses an xslt as defined in the app.config.
///
/// An HTML string containing the sitemap.
public override string ToString()
{
string result=string.Empty;
try
{
string xslt=Settings.GetSetting("SiteMapXslt");
XmlTransformer trans=new XmlTransformer(this.ToXml(),xslt);
result= trans.TransformXml();
}
catch (System.Exception ex)
{
Console.WriteLine("Error outputting html." + ex.ToString());
}
return result;
}
///
/// Returns a google sitemap compatible xml string. Note that this uses an xslt as defined in the app.config.
///
/// An XML string containing the sitemap.
public string ToGoogleSitemap()
{
string xslt=Settings.GetSetting("GoogleSiteMapXslt");
XmlTransformer trans=new XmlTransformer(this.ToXml(),xslt);
return trans.TransformXml();
}
///
/// Returns an xml string representation. Forces a regen of the xml. This is recursively called.
///
/// The xml document where the xml is going to be stored.
/// The parent node of this particular document.
/// An XML string containing the innerxml of the parent.
public string ToXml(ref XmlDocument doc, XmlNode parent)
{
string now=GetDate();
for (int i=0;i < this.Count;i++)
{
XmlNode url=AddChildNode(ref doc,parent,"url");
AddChildNode(ref doc,url,"DateOutput",now);
AddChildNode(ref doc,url,"Description",this[i].Description);
AddChildNode(ref doc,url,"Url",this[i].Url.ToString());
AddChildNode(ref doc,url,"Anchor",this[i].Anchor);
AddChildNode(ref doc,url,"Deleted",this[i].Deleted.ToString());
AddChildNode(ref doc,url,"Disabled",this[i].Disabled.ToString());
AddChildNode(ref doc,url,"Level",this[i].Level.ToString());
AddChildNode(ref doc,url,"TabOrder",this[i].TabOrder.ToString());
AddChildNode(ref doc,url,"Visible",this[i].Visible.ToString());
AddChildNode(ref doc,url,"AdminTab",this[i].AdminTab.ToString());
if (this[i].HasChildren)
{
XmlNode child=AddChildNode(ref doc, url,"Urls");
child.InnerXml=this[i].ChildTabs.ToXml(ref doc,child);
}
}
return parent.InnerXml;
}
///
/// Gets the date/time in an Xml friendly format.
///
/// The date and time in w3c format.
private string GetDate()
{
//1997-07-16T19:20:30+01:00
DateTime now=System.DateTime.UtcNow;
string year=now.Year.ToString();
string month=now.Month.ToString();
string day=now.Day.ToString();
string hour=now.Hour.ToString();
string minute=now.Minute.ToString();
string second=now.Second.ToString();
StringBuilder dateTime=new StringBuilder();
dateTime.Append(year.PadLeft(4,'0'));
dateTime.Append("-");
dateTime.Append(month.PadLeft(2,'0'));
dateTime.Append("-");
dateTime.Append(day.PadLeft(2,'0'));
dateTime.Append("T");
dateTime.Append(hour.PadLeft(2,'0'));
dateTime.Append(":");
dateTime.Append(minute.PadLeft(2,'0'));
dateTime.Append(":");
dateTime.Append(second.PadLeft(2,'0'));
return dateTime.ToString();
}
///
/// Returns this tab list as an xml document. If the document has already been created, it just returns the existing document.
///
/// A string containing the xml for this TabList
public string ToXml()
{
if (m_xml ==string.Empty)
{
XmlDocument doc=new XmlDocument();
XmlNode root=doc.CreateElement("SiteMap");
doc.AppendChild(root);
XmlNode urls=AddChildNode(ref doc, root, "Urls");
ToXml(ref doc,urls);
m_xml=doc.OuterXml;
}
return m_xml;
}
///
/// Adds a child node to the XmlDocument.
///
///
///
///
///
private XmlNode AddChildNode(ref XmlDocument doc, XmlNode parent, string nodeName)
{
return AddChildNode(ref doc,parent,nodeName,string.Empty);
}
///
/// Adds a child node tot he XmlDocument.
///
///
///
///
///
///
private XmlNode AddChildNode(ref XmlDocument doc, XmlNode parent, string nodeName, string nodeValue)
{
XmlNode node=doc.CreateElement(nodeName);
if (nodeValue != string.Empty)
{
node.InnerText=nodeValue;
}
parent.AppendChild(node);
return node;
}
///
/// Loads the portal settings from the database.
///
private void LoadPortalSettings()
{
if (m_portalSettings==null)
{
DataSet ds=SqlHelper.ExecuteDataset(Settings.GetSetting("DotNetNukeConnectionString"),"GetPortalSettings",new object[]{m_portalId});
m_portalSettings=ds.Tables[0].Rows[0];
}
}
}
}
App.Config
xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="DotNetNukeConnectionString" value="Data Source=MySource;User Id=MyUser;Password=MyPassword;Initial Catalog=DotNetNuke"/>
<add key="SnowballConnectionString" value="Data Source=MySource;User Id=MyUser;Password=MyPassword;Initial Catalog=Mydatabase"/>
<add key="SiteMapXslt" value="c:\snowball\SiteMapGenerator\Xslt\SiteMapXslt.xslt"/>
<add key="GoogleSiteMapXslt" value="c:\snowball\SiteMapGenerator\Xslt\GoogleSiteMapXslt.xslt"/>
<add key="Portals" value="0|http://www.mysite.com/|c:\temp\"/>
<add key="HtmlFileName" value="SiteMap.html"/>
<add key="XmlFileName" value="XmlSiteMap.xml"/>
<add key="GoogleSiteMapFileName" value="sitemap.xml"/>
</< SPAN>appSettings>
< SPAN></configuration>
GoogleSiteMapXslt.xslt
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="iso-8859-1" indent="yes"/>
<xsl:template match="*">
<xsl:element name="urlset">
<xsl:apply-templates select="//url[AdminTab='False' and Visible='True' and Deleted='False' and Disabled='False']"/>
</< SPAN>xsl:element>
</< SPAN>xsl:template>
<xsl:template match="url">
<xsl:element name="url">
<xsl:element name="loc"><xsl:value-of select="Url"/></< SPAN>xsl:element>
<xsl:element name="lastmod"><xsl:value-of select="DateOutput"/></< SPAN>xsl:element>
<xsl:element name="changefreq">daily</< SPAN>xsl:element>
</< SPAN>xsl:element>
</< SPAN>xsl:template>
< SPAN></xsl:stylesheet>
SiteMapXslt.Xslt
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" version="1.0" encoding="iso-8859-1" indent="yes"/>
<xsl:template match="*">
<HTML>
<HEAD id="Head">
<TITLE>
Site Map
</< SPAN>TITLE>
</< SPAN>HEAD>
<BODY id="Body" BOTTOMMARGIN="0" LEFTMARGIN="0" TOPMARGIN="0" RIGHTMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0">
<xsl:apply-templates select="Urls"/>
</< SPAN>BODY>
< SPAN></HTML>
</< SPAN>xsl:template>
<xsl:template match="Urls">
<xsl:element name="UL">
<xsl:apply-templates select="url[AdminTab='False' and Visible='True' and Deleted='False' and Disabled='False']">
</< SPAN>xsl:apply-templates>
</< SPAN>xsl:element>
</< SPAN>xsl:template>
<xsl:template match="url">
<xsl:value-of select="Anchor" disable-output-escaping="yes"/><br/>
<xsl:apply-templates select="Urls"></< SPAN>xsl:apply-templates>
< SPAN></xsl:template>
< SPAN></xsl:stylesheet>