Tuesday, January 15, 2008

Lots of folks have asked me how to add various XMLism like XML Namespace prefixes to the serialized output of a SyndicationFeed. This is actually easy to do once you know the trick but it's admittedly not the most obvious thing in the world.

The thing to remember is that the System.Xml stack treats prefix declarations as special kinds of attributes. If you want to emit an XML namespace declaration of xmlns:contoso=http://schemas.contoso.com you need to emit attribute whose name is the prefix you're declaring (e.g. "contoso"), whose value is the namespace URI that corresponds to the prefix (e.g. 'http://schemas.contoso.com'). This attribute needs to be in the special XML namespace declaration namespace (!) of http://www.w3.org/2000/xmlns/

Since SyndicationFeed supports additional XML attributes through the AttributeExtensions property, you can do this on SyndicationFeed as follows (using the C# 3.0 collection initializer syntax, natch):

SyndicationFeed feed = new SyndicationFeed()
{

   AttributeExtensions =

  {
     { new XmlQualifiedName("contoso", "
http://www.w3.org/2000/xmlns/"), "http://schemas.constoso.com" }
  }
};

If you like syntactic sugar, here are a few extension methods that add a helper function to all of the OM constructs that support attribute extensibility:

using System;
using System.Xml;
using System.ServiceModel.Syndication;

namespace Samples
{
    public static class SyndicationExtensions
    {
        public static void DeclareNamespace(this SyndicationFeed feed, string prefix, string nsUri)
        {
            feed.AttributeExtensions.Add(new XmlQualifiedName( prefix, "
http://www.w3.org/2000/xmlns/" ), nsUri);
        }

        public static void DeclareNamespace(this SyndicationItem item, string prefix, string nsUri)
        {
            item.AttributeExtensions.Add(new XmlQualifiedName(prefix, "
http://www.w3.org/2000/xmlns/"), nsUri);
        }

        public static void DeclareNamespace(this SyndicationCategory category, string prefix, string nsUri)
        {
            category.AttributeExtensions.Add(new XmlQualifiedName(prefix, "
http://www.w3.org/2000/xmlns/"), nsUri);
        }

        public static void DeclareNamespace(this SyndicationLink link, string prefix, string nsUri)
        {
            link.AttributeExtensions.Add(new XmlQualifiedName(prefix, "
http://www.w3.org/2000/xmlns/"), nsUri);
        }

        public static void DeclareNamespace(this SyndicationPerson person, string prefix, string nsUri)
        {
            person.AttributeExtensions.Add(new XmlQualifiedName(prefix, "
http://www.w3.org/2000/xmlns/"), nsUri);
        }
    }
}

On a side note, I'm becoming a huge fan of extension methods. They are not perfect, but I expect that their existence will have a pretty substantial impact on the way the internals of the framework get factored in future versions...

Tuesday, January 15, 2008 12:07:00 AM (Pacific Standard Time, UTC-08:00)  #    Comments [1]
Wednesday, January 16, 2008 3:33:20 AM (Pacific Standard Time, UTC-08:00)
Hello.

yep, that is something that will work. However, what i'd like to know is how to put those attributes on the <rss> element. Even though I've just taken a peak at the code through reflector, it seems like the <rss> tag will always be generated without any attributes and I'm not sure if there's an easy way to intercept the generation and add the xml namespace declarations there.

One more thing: why can I generate a feed from syndicationfeed object that hasn't set up the link element? isn't that element mandatory? For instance, if you open the picture services sample on FF, it won't apply the default rss style sheet to it until you add a <link> element to the top syndicationfeed object you're using...

thanks.
Comments are closed.