tags:

views:

294

answers:

1

Just took a stab at creating an aggregate feed - from two separate Atom feeds - sorted descending by published date...

UPDATE: Thanks to Martin Honnen (MVP) over at http://social.msdn.microsoft.com/Forums/en-US/categories/ - combined with a safe XElement.Load(url) helper (and iterator block)... I think the code below is a pretty good approach for aggregating Xml documents (aggregate sitemaps in this case - although this can easily be adapted for Atom or RSS feeds).

The namespace conversion helper below converts elements only and not attributes (although that too can be added).

static void Main(string[] args)
{
    XDocument feed = MergeSiteMaps(new List<string>() { "http://www.58bits.com/blog/googleSitemap.ashx", "http://www.58bits.com/otherblog/googleSiteMap.ashx",  "http://www.58bits.com/photos/sitemap.xml"});

    XNamespace sm = "http://www.sitemaps.org/schemas/sitemap/0.9";

    foreach (XElement location in feed.Root.Elements(sm + "url").Elements(sm + "loc")) 
    {
        Console.WriteLine((string)location); 
    } 
}

public static XDocument MergeSiteMaps(IEnumerable<string> urls)
{
    XNamespace sm = "http://www.sitemaps.org/schemas/sitemap/0.9";
    XNamespace xsi = "http://www.w3.org/2001/XMLSchema-instance";
    XNamespace xsd = "http://www.w3.org/2001/XMLSchema";
    string schemaLocation = "http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd";

    //Our container sitemap document
    return new XDocument(
        new XDeclaration("1.0", "utf-8", "yes"),
        new XElement(sm + "urlset",
            new XAttribute(XNamespace.Xmlns + "xsi", xsi),
            new XAttribute(XNamespace.Xmlns + "xsd", xsd),
            new XAttribute(xsi + "schemaLocation", schemaLocation),

            new XElement(sm + "url",
                new XElement(sm + "loc", "http://www.58bits.com/"),
                new XElement(sm + "lastmod", DateTime.Now.ToString("yyyy-MM-dd")),
                new XElement(sm + "changefreq", "monthly"),
                new XElement(sm + "priority", "1.0")),

            new XElement(sm + "url",
               new XElement(sm + "loc", "http://www.58bits.com/default.aspx"),
               new XElement(sm + "lastmod", DateTime.Now.ToString("yyyy-MM-dd")),
               new XElement(sm + "changefreq", "monthly"),
               new XElement(sm + "priority", "1.0")),

            GetElements(sm, urls, "url"))
        );
}

private static IEnumerable<XElement> GetElements(XNamespace ns, IEnumerable<string> urls, string elementLocalName)
{
    XElement source;

    foreach (string url in urls)
    {
        try
        {
            source = XElement.Load(url);
        }
        catch (Exception ex)
        {
            //TODO: Log the Url that failed
            string message = ex.Message;
            continue;
        }

        XNamespace defaultNamespace = source.GetDefaultNamespace();
        bool differentNamespace = (ns != defaultNamespace);
        foreach (XElement element in source.Elements(defaultNamespace + elementLocalName))
        {
            if (differentNamespace)
                ChangeNamespace(ns, element);
            yield return element;
        }
    }
}

private static void ChangeNamespace(XNamespace ns, XElement entry)
{
    foreach (XElement e in entry.DescendantsAndSelf())
    {
        if (e.Name.Namespace != XNamespace.None)
        {
            e.Name = ns.GetName(e.Name.LocalName);
        }
    }
}
A: 

I would look into the SyndicationFeed Class. Here is a sample of generating a feed using this.

private static SyndicationFeed CreateFeed(List<SyndicationItem> items)
{
    // Create the list of syndication items. These correspond to Atom entries
    SyndicationFeed feed;

    // create the feed containing the syndication items.
    feed = new SyndicationFeed()
    {
        // The feed must have a unique stable URI id
        Id = "http://example.com/MyFeed",
        Title = new TextSyndicationContent("My Feed"),
        Items = items
    };
    feed.AddSelfLink(WebOperationContext.Current.IncomingRequest.GetRequestUri());
    return feed;
}

private static SyndicationItem CreateItem()
{
    var item = new SyndicationItem()
       {
           // Every entry must have a stable unique URI id
           Id = id.ToString(),
           Title = new TextSyndicationContent(title),
           // Every entry should include the last time it was updated
           LastUpdatedTime = startDate,
           // The Atom spec requires an author for every entry. If the entry has no author, use the empty string
           Authors = 
               { 
                   new SyndicationPerson() 
                       {
                           Name = author.Name,
                           Email = author.EmailAddress,
                           Uri = author.Website
                       }
               },
           // The content of an Atom entry can be text, xml, a link or arbitrary content. In this sample text content is used.
           Content = new TextSyndicationContent(description),
       };

    return item;
}
bendewey