Technolog

Blogging over technologie.
Welcome to Technolog Sign in | Join | Help
in Search

eprogrammer

SiteMaps made easy

 

If you’re a site admin or asp.net developer for an internet site, you certainly need to look into sitemaps, if you want to perform SEO.

It’s not necessary to  simply crawl your own site and then to give every page a priority, but consider this for a forum or other pages which are irregularly or often updated. If you don’t want to have crawlers do unneeded roundtrips, implement a sitemap.

‘robots.txt’ should contain a reference to your map eg. Sitemap: http://www.myfantasticsite.com/sitemap.xml

Ideas of this class, written using C#, can be found anywhere on the net. However, as some might know me, I like it to be finished and neat and a self-supporting class ready for usage (e.g. it must not be written to a string to add or remove wished attributes that the serializer could not handle).

The following things are solved. 
Since  ‘changefreq’ and ‘lastmod’ and ‘priority’ are optional values, you don’t want the XmlSerializer to create empty tags!
This is done by adding a DefaultValue attribute. It will cause XmlSerializer to check the current value against the default value. If they are equal, it is considered to be an empty non existing tag. Remember, that the defaultvalues need to be out of the range of possible values! Therefore, EnumChangeFreq contains an extra member ‘notused’
An other solved issue is the xsi:schemaLocation attribute at documentelement level. You cannot add this using the XmlSerializerNamespaces class. It would simply fail on xsi:schemaLocation.

Do not use: (XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("xsi:schemaLocation", "
http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd");)


The solution was to serialize the XML to a XmlDocument and to append the needed attributes as seen below.
You can use the class as follows.
UrlSet retVal = new UrlSet();

(simplified you can add your algorithm to retrieve the real lastmodified time)

retVal.AddUrl(new Url() { LastModifiedDateTime = DateTime.Now.ToUniversalTime(), Loc = “http://www.myfantasticsite.com/blah.aspx”) });

Retrieve the XML sitemap string.
string xml = null;
using (var io = (MemoryStream)retVal.ToStream())
{
                xml =  new UTF8Encoding().GetString(io.ToArray());
}

Since method returns a Stream object, you also can use it to directly serialize it to disk. There might be no need for roundtrips to slower string(s).

using System;
using System.Xml;
using System.Xml.Serialization;
using System.ComponentModel;
using System.IO;

namespace adccure
{

    public enum EnumChangeFreq
    {
        notset,
        always,
        hourly,
        daily,
        weekly,
        monthly,
        yearly,
        never
    }
[XmlRoot(  ElementName = "urlset", Namespace = "http://www.sitemaps.org/schemas/sitemap/0.9")]
public sealed class UrlSet
    {       
        private Url[] _url;
        public void AddUrl(Url url)
        {
            int l = _url.Length + 1;
            Array.Resize(ref _url, l);
            _url[l - 1] = url;
        }

        public UrlSet()
        {
            _url = new Url[0];
        }
        [XmlElement(ElementName = "url")]
        public Url[] url
        {
            get { return _url; }
            set { _url = value; } //bogus
        }
        /// <summary>
        /// serializes the UrlSet to a sitemap.xsd conform string ready for saving to disk.
        /// </summary>
        /// <returns>a Stream object</returns>
        public Stream ToStream()
        {
            XmlSerializer xmlser = new XmlSerializer(this.GetType());

            XmlDocument doc = new XmlDocument();
            var io = new MemoryStream();
            xmlser.Serialize(io, this);
            io.Position = 0;
            doc.Load(io);
            var attr = doc.CreateAttribute("schemaLocation", "http://www.w3.org/2001/XMLSchema-instance");
            attr.Value = "http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd";
            doc.DocumentElement.Attributes.Append(attr);
            io.Position = 0;
            doc.Save(io);
            io.Position = 0;
            return io;
        }
    }

    public sealed class Url
    {
        private string _loc;
        private DateTime _lastmod;
        private float _priority;
        private EnumChangeFreq _changefreq;

        public Url()
        {
            //setting defaults
            _changefreq = EnumChangeFreq.notset;
            _priority = 0.0F;
            _lastmod = DateTime.MinValue;
        }

        [XmlElement(ElementName = "loc")]
        public string Loc
        {
            get
            {
                return _loc;
            }

            set
            {
                if (string.IsNullOrEmpty(value))
                {
                    throw new ArgumentNullException();
                }
                if (value.Length < 12 || value.Length > 2048)
                {
                    throw new ArgumentException("loc must be between 12 and 2048 in length");
                }
                _loc = value;
            }
        }
        [XmlElement(ElementName = "lastmod"), DefaultValue(typeof(DateTime), "1-1-0001")]
        public DateTime LastModifiedDateTime
        {
            get
            {
                return _lastmod;
            }

            set
            {
                _lastmod = new DateTime(value.Year, value.Month, value.Day, value.Hour, value.Minute, value.Second, value.Kind);

            }
        }
        [XmlElement(ElementName = "changefreq")]
        [DefaultValue(EnumChangeFreq.notset)]
        public EnumChangeFreq ChangeFreq
        {
            get
            {
                return _changefreq;
            }

            set
            {
                _changefreq = value;
            }
        }
        [XmlElement(ElementName = "priority")]
        [DefaultValue(0.0F)]
        public float Priority
        {
            get
            {
                return _priority;
            }

            set
            {
                if (value < 0 || value > 1.0)
                {
                    throw new ArgumentException("Must be between 0 and 1");
                }
                _priority = value;
            }
        }
    }
}

Tags van Technorati: ,,
Published Sunday, January 31, 2010 6:12 PM by eprogrammer

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

No Comments

Leave a Comment

(required) 
(optional)
(required) 
Submit

About eprogrammer

Egbert Nierop is enthousiast C# en ASP.NET evangelist . Egbert Nierop is zelfstandige en houdt van projecten met een hoog technologische uitdaging.
Powered by Community Server, by Telligent Systems