locked
Build custom menu's and Meta-tags from you web.sitemap RRS feed

  • Question

  • User1633968479 posted

    Nothing new, just an interesting way to use your sitemap for building a custom menu (unordered list), metatags, ...

    I use this in my masterpage to set all page-titles, descriptions, metatags and the menu.

    Happy programming...

    The codebehind...

        Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            Dim currClass As String = String.Empty
            If SiteMap.CurrentNode.Url = SiteMap.RootNode.Url Then currClass = "class='current'"
            menudiv.InnerHtml = _
                String.Format("<ul><li style='border:none;'><a " & currClass & " href=""{0}"">{1}</a></li>{2}</ul>", _
                          SiteMap.RootNode.Url, SiteMap.RootNode("menutext"), _
                          GetMenuList()) 
        End Sub
        Private Function getMenuList() As String
            Dim siteMapView As SiteMapDataSourceView = CType(SiteMapData.GetView(String.Empty), SiteMapDataSourceView)
            Dim nodes As SiteMapNodeCollection = CType(siteMapView.Select(DataSourceSelectArguments.Empty), SiteMapNodeCollection)
            Return GetNodeInfo(nodes)
        End Function
        Private Function GetNodeInfo(ByVal nodes As SiteMapNodeCollection) As String
            Dim currClass As String = String.Empty
            Dim sResult As String = String.Empty
            For Each node As SiteMapNode In nodes
                If Not node("ShowInMenu") = "false" Then
                    If node.Url = SiteMap.CurrentNode.Url Then currClass = "class='current'"
                    sResult &= String.Format("<li><a {0} href=""{1}"">{2}</a>", currClass, node.Url, node("menutext"))
                    If node.HasChildNodes Then
                        sResult &= String.Format("<ul>{0}</ul>", GetNodeInfo(node.ChildNodes))
                    End If
                    sResult &= "</li>"
                End If
            Next
            Return sResult
        End Function
        Protected Overrides Sub OnInit(ByVal e As System.EventArgs)
            MyBase.OnInit(e)
            If SiteMap.CurrentNode IsNot Nothing Then
                Page.Title = SiteMap.CurrentNode.Title
                If SiteMap.CurrentNode("revisit") IsNot Nothing Then
                    Dim meta As New HtmlMeta()
                    meta.Name = "revisit-after"
                    meta.Content = SiteMap.CurrentNode("revisit").ToString
                    Page.Header.Controls.AddAt(0, meta)
                End If
                If SiteMap.CurrentNode("robots") IsNot Nothing Then
                    Dim meta As New HtmlMeta()
                    meta.Name = "robots"
                    meta.Content = SiteMap.CurrentNode("robots").ToString
                    Page.Header.Controls.AddAt(0, meta)
                End If
                If SiteMap.CurrentNode("keywords") IsNot Nothing Then
                    Dim meta As New HtmlMeta()
                    meta.Name = "keywords"
                    meta.Content = "" & SiteMap.CurrentNode("keywords")
                    Page.Header.Controls.AddAt(0, meta)
                End If
                If SiteMap.CurrentNode.Description IsNot Nothing Then
                    Dim meta As New HtmlMeta()
                    meta.Name = "Description"
                    meta.Content = SiteMap.CurrentNode.Description.ToString()
                    Page.Header.Controls.AddAt(0, meta)
                End If
            End If
        End Sub

    The sitemap...

    <?xml version="1.0" encoding="utf-8" ?>
    <siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" enableLocalization="true">
        <siteMapNode url="~/default.aspx" title="$resources: Lang,PageTitle_Home, Home" menutext="$resources: Lang,MenuText_Home, Home" description="" keywords="" revisit="" robots="">
            <siteMapNode url="services.aspx" title="" menutext="" description="" keywords="" revisit="" robots="">
                <siteMapNode url="design.aspx" title="" menutext="" description="" keywords="" revisit="" robots="" />
                <siteMapNode url="development.aspx" title="" menutext="" description="" keywords="" revisit="" robots="" />
                <siteMapNode url="maintenance.aspx" title="" menutext="" description="" keywords="" revisit="" robots="" />
            </siteMapNode>
            <siteMapNode url="hosting.aspx" showinmenu="false" title="" menutext="" description="" keywords="" revisit="" robots="" />
            <siteMapNode url="Portfolio.aspx" title="" menutext="" description="" keywords="" revisit="" robots="" />
        </siteMapNode>
    </siteMap>
    



     

    Saturday, January 9, 2010 9:46 AM

All replies

  • User2130758966 posted

    Nice code! I wrote about a similar way to do this in an article once but it was c#. I  put a list of other uses at the end of my article but it never occurred to embed the robots meta into the web.sitemap so thanks for the idea.

    Saturday, January 9, 2010 11:30 AM
  • User1633968479 posted

    Hi Harry,

    Great article and well comented! I'm afraid my english isn't good enough to write these kind of articles, so keep up the good work!!!

    Johny 

    Saturday, January 9, 2010 1:20 PM
  • User-226523053 posted

    Hello Jonhy,

    Maybe you can help me, I'm reading your article and its great it works perfectly for me, thank you very much, I set your code in my master.page and now all the pages of my site take their title and description metas from the sitemap.
     
    But I need one more think, I have 2 sitemap providers in my web.config each one for each language of my site.
     
    How can I change the provider in the masterpage to make the meta title and meta description works with the apropiate provider?
     
    Thank you very much.


    Wednesday, February 17, 2010 7:05 AM
  • User1633968479 posted

    I've adjusted the code a bit:

    • <table> tags when the browser is IE6 or older;
    • injection of a <h1> headerlabel in the contentpages
    • replace breaks and whitespaces in generated html by string.empty (smaller page-size > faster)
    • move the viewstate-information to the end of the page (makes life a bit easyer for search-engines)

    Have fun...

     

        Protected Overrides Sub OnInit(ByVal e As System.EventArgs)
            MyBase.OnInit(e)
            If SiteMap.CurrentNode IsNot Nothing Then
                Page.Title = SiteMap.CurrentNode.Title
                If Not SiteMap.CurrentNode.Url = SiteMap.RootNode.Url Then
                    If SiteMap.CurrentNode("headertext") IsNot Nothing Then
                        If Not String.IsNullOrEmpty(SiteMap.CurrentNode("headertext")) Then
                            Dim lbl As New Label
                            lbl.Text = "<hr /><h1>" & SiteMap.CurrentNode.Title & "</h1>"
                            cph.Controls.AddAt(0, lbl)
                        End If
                    End If
    
                Else
                    SiteMapPath.Visible = False
                End If
                createMetaTag("revisit-after")
                createMetaTag("robots")
                createMetaTag("keywords")
                createMetaTag("description")
            End If
        End Sub
        Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            menudiv.InnerHtml = String.Format("<ul id=""menu""><li style='border:none;'><a href=""{0}"" style=""border:0;"">{1}</a></li>{2}</ul>", _
                                SiteMap.RootNode.Url, SiteMap.RootNode("menutext"), _
                                getMenuList())
        End Sub
        Private Function getMenuList() As String
            Dim siteMapView As SiteMapDataSourceView = CType(SiteMapData.GetView(String.Empty), SiteMapDataSourceView)
            Dim nodes As SiteMapNodeCollection = CType(siteMapView.Select(DataSourceSelectArguments.Empty), SiteMapNodeCollection)
            Return GetNodeInfo(nodes)
        End Function
        Private Function GetNodeInfo(ByVal nodes As SiteMapNodeCollection) As String
            Dim sResult As String = String.Empty
            Dim MenuFormat As String = "<table><tr><td><ul>{0}</ul></td></tr></table></a>"
            If Not CheckForIE6() Then MenuFormat = "</a><ul>{0}</ul>"
            For Each node As SiteMapNode In nodes
                If Not node("ShowInMenu") = "false" Then
                    sResult &= String.Format("<li><a href=""{0}"">{1}", node.Url, node("menutext"))
                    If node.HasChildNodes Then
                        sResult &= String.Format(MenuFormat, GetNodeInfo(node.ChildNodes))
                    Else : sResult &= "</a>"
                    End If
                End If
                sResult &= "</li>"
            Next
            Return sResult
        End Function
        Protected Sub createMetaTag(ByRef TagName As String)
            Dim node As SiteMapNode = SiteMap.CurrentNode
            If Not node(TagName) Is Nothing Then
                If Not String.IsNullOrEmpty(node(TagName)) Then
                    Dim meta As New HtmlMeta()
                    meta.Name = TagName
                    meta.Content = node(TagName).ToString
                    Page.Header.Controls.AddAt(0, meta)
                End If
            End If
        End Sub
        Protected Function CheckForIE6() As Boolean
            If Request.Browser.Type.Contains("IE") And Request.Browser.MajorVersion < 7 Then
                Return True
            Else
                Return False
            End If
        End Function
        Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter)
            Dim REGEX_BETWEEN_TAGS As Regex = New Regex(">\s+<", RegexOptions.Compiled)
            Dim REGEX_LINE_BREAKS As Regex = New Regex(">\n\s+<", RegexOptions.Compiled)
            Dim REGEX_RETURNS As Regex = New Regex("\r\s+", RegexOptions.Compiled)
            Dim html As String
            Using htmlwriter As New HtmlTextWriter(New System.IO.StringWriter())
                MyBase.Render(htmlwriter)
                html = htmlwriter.InnerWriter.ToString()
                html = REGEX_BETWEEN_TAGS.Replace(html, "><")
                html = REGEX_LINE_BREAKS.Replace(html, " ")
                html = REGEX_RETURNS.Replace(html, " ")
                Dim StartPoint As Integer = html.IndexOf("<input type=""hidden"" name=""__VIEWSTATE""")
                If StartPoint >= 0 Then
                    Dim EndPoint As Integer = html.IndexOf("/>", StartPoint) + 2
                    Dim ViewStateInput As String = html.Substring(StartPoint, EndPoint - StartPoint)
                    html = html.Remove(StartPoint, EndPoint - StartPoint)
                    Dim FormEndStart As Integer = html.IndexOf("</form>")
                    If FormEndStart >= 0 Then
                        html = html.Insert(FormEndStart, ViewStateInput)
                    End If
                End If
                writer.Write(html.Trim())
            End Using
        End Sub
    


     

    Wednesday, February 17, 2010 7:11 AM
  • User1633968479 posted

    Hi Iorien,

    I'm sorry, but I don't know a way to change the default sitemapprovider at runtime, I don't think it's possible.

    As far as I can see this lets two options open for you:

    1. You can use resourcefiles to do the translation. (see my first example: title="$resources: Lang,PageTitle_Home, Home")
    2. Add a SiteMapDatasource from the toolbox to your page and adapt the code to use this datasource. The SiteMapDatasource allows you to change the provider at runtime.

    Good luck,

     

     

    Wednesday, February 17, 2010 7:31 AM
  • User-226523053 posted

    Hello Johny,

    Thank you for your answer, the first option is not possible because the sitemaps are differnt from each language, not only the language but the structure.

    I'm able to make my web controls (menu, sitemappath) work with the correct provider setting the correct SiteMapProvider of the SiteMapDataSource from codebehind. But the metas (created in my masterpage) continue woorking with the defaultProvider.

    I don' know how to solve this.

    Wednesday, February 17, 2010 10:02 AM
  • User1633968479 posted

    If you have a sitemapdatasource on the page, you can use this code:

        Protected Overrides Sub OnInit(ByVal e As System.EventArgs)
            MyBase.OnInit(e)
            Dim node As SiteMapNode
            If SiteMapDataSource1.Provider.CurrentNode IsNot Nothing Then
                node = SiteMapDataSource1.Provider.CurrentNode
                Page.Title = node.Title
                If Not node.Url = SiteMap.RootNode.Url Then
                    If node("headertext") IsNot Nothing Then
                        If Not String.IsNullOrEmpty(node("headertext")) Then
                            Dim lbl As New Label
                            lbl.Text = "<h1>" & node.Title & "</h1>"
                            cph.Controls.AddAt(0, lbl) 'cph is a contentplaceholder
                        End If
                    End If
                Else
                    SiteMapPath.Visible = False
                End If
                createMetaTag("revisit-after", node)
                createMetaTag("robots", node)
                createMetaTag("keywords", node)
                createMetaTag("description", node)
            End If
        End Sub
        Protected Sub createMetaTag(ByRef TagName As String, ByRef node As SiteMapNode)
            If Not node(TagName) Is Nothing Then
                If Not String.IsNullOrEmpty(node(TagName)) Then
                    Dim meta As New HtmlMeta()
                    meta.Name = TagName
                    meta.Content = node(TagName).ToString
                    Page.Header.Controls.AddAt(0, meta)
                End If
            End If
        End Sub
    


     

    Wednesday, February 17, 2010 4:00 PM
  • User-226523053 posted

    Hello Johny ,

    you've been very helpful. Thank you very much!

    Friday, February 19, 2010 10:28 AM
  • User-160125345 posted

    Hi

    Thats great code I was interested in the meta codeing as I wanted an easier way to up data meta infoamtion. I have converted that part to C# for anyone interested

    Hope this helps

    This is the code in my master page

     

     Code in C#

     Along with the site map

     

    Tuesday, June 8, 2010 3:20 AM
  • User-1403089579 posted

    Hi, where is the C# code?

    Thanks.


    Monday, August 9, 2010 12:38 PM