XML Linq requires correct namespace for all XElements

I've been teaching myself ASP.Net MVC during any free time I get at the weekends. I started a simple test project which has developed into the events section on NIMTUG. Yesterday I was looking for a way to easily create search engine sitemaps for the event and sepaker pages and I found Robert Tennyson's post Dynamic sitemaps with ASP.NET MVC which seems very easy indeed. With a couple of changes I had the sitemaps working and so submitted them to google only to be notified a couple of hours later that they had failed with the error "Invalid Namespace".

I should have validated the outputed Xml using the Google Sitemap Validator but instead I had only tested the xml output in the browser which hid the root namespace (xmlns attribute) but more importantly also hid an empty namespace on all the url elements.

 

<?xml version="1.0" encoding="utf-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url xmlns="">
    <loc>http://nimtug.org/events/speaker/details/41</loc>
   <lastmod>2009-05-23</lastmod>
  </url>
  <url xmlns="">
    <loc>http://nimtug.org/events/speaker/details/23</loc>

    <lastmod>2009-05-23</lastmod>
  </url> 

 

It appears that with LINQ to XMl you have to add the correct namespace to every XmlElement which seems like over kill to me as the child elements are supposed to inherit their namespace from their parent (as you would expect) - if anyone knows of an easier way please let me know. My fix was to just add the namespace to each XElement constructor.

protected string GetAlsoluteUrl(object routeValues)
{
    var values = new RouteValueDictionary(routeValues);
    var context = new RequestContext(HttpContext, RouteData);

    string url = RouteTable.Routes.GetVirtualPath(context, values).VirtualPath;

    return new Uri(Request.Url, url).AbsoluteUri;
}

protected ActionResult CreateSiteMap<TModel, TID>(IEnumerable<TModel> items, Func<TModel, TID> getID,
                                                  string controllerName, string actionName)
{
    // XML LINQ requires that ALL XElements have the correct namespace 
    XNamespace xmlns = "http://www.sitemaps.org/schemas/sitemap/0.9";

    var root = new XElement(xmlns + "urlset");
    foreach (TModel item in items)
    {
        object routeValues =
            new
                {
                    id = getID(item),
                    controller = controllerName,
                    action = actionName
                };


        // only add last modified element if we can get the date
        XElement lastMod = null;
        var lm = item as IObjectTimes;
        if (lm != null)
        {
            lastMod = new XElement(xmlns + "lastmod", (lm.Updated ?? lm.Created).ToString("yyyy-MM-dd"));
        }
        root.Add(new XElement(xmlns + "url",
                              new XElement(xmlns + "loc", GetAlsoluteUrl(routeValues)), lastMod
                     )
            );
    }


    using (var memoryStream = new MemoryStream())
    {
        using (var writer = new StreamWriter(memoryStream, Encoding.UTF8))
        {
            root.Save(writer);
        }

        return Content(Encoding.UTF8.GetString(memoryStream.ToArray()), "text/xml", Encoding.UTF8);
    }
}
Published 24 May 2009 20:58 by Damien McGivern
Filed under: , ,

Comments

# re: XML Linq requires correct namespace for all XElements

09 June 2009 07:38 by John Kaster

FWIW, I just ran into that same implementation issue today. It is indeed onerous to have to reference the namespace in every XElement reference. I hope better default behavior is supported in the future.

Leave a Comment

(required) 
(required) 
(optional)
(required)