Transforming RSS and Atom feeds

2006 August 25
by Karen

I’m still working on getting Coldfusion to transform RSS and Atom feeds into HTML and I’ve got stylesheets that work for each of the flavors of these RSS 0.9, 1.0, and 2.0 and Atom 1.0 and 0.3 . However, I’m having troubling with getting Coldfusion to tell that an Atom 0.3 feed is that so that I can use the proper transformation. After doing some background reading on Atom 0.3 I found out that it is deprecated. So, I’m not going to support this feed in my tool. Instead the tool will send an error message for this type of feed any other feed type it can’t recognize.

Below is my XSLT code that checks to see what kind of feed is being processed and then uses the correct templates for that type of feed.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:atom="http://www.w3.org/2005/Atom"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:foo="http://purl.org/rss/1.0/"
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
    xmlns:admin="http://webns.net/mvcb/"
    xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:wfw="http://wellformedweb.org/CommentAPI/"
    version="1.0">
    <xsl:output method="html"/>
    <xsl:template match="/">
    <xsl:choose>
        <xsl:when test="atom:feed/atom:subtitle">
            <xsl:text>ATOM 1.0</xsl:text>
            <xsl:element name="h1"><xsl:value-of select="atom:feed/atom:title"/></xsl:element>
            <xsl:element name="ul">

                <xsl:for-each select="atom:feed/atom:entry">
                    <xsl:element name="li">
                        <xsl:element name="h2"><xsl:element name="a">
                            <xsl:attribute name="href">
                                <xsl:value-of select="atom:link[@rel='alternate']/@href"/>
                            </xsl:attribute>
                            <xsl:value-of select="atom:title"/>
                        </xsl:element></xsl:element>
                        <xsl:if test="atom:published">
                            <xsl:element name="div">
                                <xsl:attribute name="class">published</xsl:attribute>
                                Published: <xsl:value-of select="atom:published"/>
                            </xsl:element>
                        </xsl:if>
                        <xsl:if test="atom:updated">
                            <xsl:element name="div">
                                <xsl:attribute name="class">updated</xsl:attribute>
                                    Updated: <xsl:value-of select="atom:updated"/>
                            </xsl:element>
                        </xsl:if>
                        <xsl:element name="div">
                            <xsl:attribute name="class">entrydesc</xsl:attribute>
                            <xsl:if test="atom:summary[@type='html']">
                                <xsl:value-of select="atom:summary" disable-output-escaping="yes" />
                            </xsl:if>

                            <xsl:if test="atom:summary[@type='text']">
                                <xsl:value-of select="atom:summary" disable-output-escaping="no" />
                            </xsl:if>
                        </xsl:element>
                    </xsl:element>
                </xsl:for-each>
            </xsl:element>
        </xsl:when>
        <xsl:when test="/rdf:RDF">
            <xsl:text>RSS 1.0</xsl:text>
            <xsl:apply-templates select="/rdf:RDF/foo:channel"/>
        </xsl:when>
        <xsl:when test="/rss/channel">
            <xsl:text>RSS</xsl:text>
            <xsl:apply-templates select="/rss/channel"/>
        </xsl:when>
        <xsl:otherwise>
            <xsl:text>I don't know</xsl:text>
         </xsl:otherwise>
    </xsl:choose>
    </xsl:template>
    <xsl:template match="/rdf:RDF/foo:channel">
        <xsl:element name="h1">
                <xsl:value-of select="foo:title"/>
        </xsl:element>
        <xsl:element name="ul">
                <xsl:apply-templates select="/rdf:RDF/foo:item"/>
        </xsl:element>
    </xsl:template>
    <xsl:template match="/rdf:RDF/foo:item">
        <xsl:element name="li">
            <xsl:element name="h2"><xsl:element name="a">
                <xsl:attribute name="href">
                    <xsl:value-of select="foo:link"/>
                </xsl:attribute>
                <xsl:attribute name="title">
                    <xsl:value-of select="foo:description"/>
                </xsl:attribute>
                <xsl:value-of select="foo:title"/>
            </xsl:element></xsl:element>
            <xsl:if test="dc:date">
                <xsl:element name="div">
                    <xsl:attribute name="class">published</xsl:attribute>
                    Published: <xsl:value-of select="dc:date"/>
                </xsl:element>
            </xsl:if>
            <xsl:element name="div">
                <xsl:attribute name="class">entrydesc</xsl:attribute>
                <xsl:choose>
                    <xsl:when test="content:encoded">
                        <xsl:value-of select="content:encoded" disable-output-escaping="yes" />
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="foo:description" disable-output-escaping="no" />
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:element>
        </xsl:element>
    </xsl:template>
    <xsl:template match="/rss/channel">
        <xsl:element name="h1">
                <xsl:value-of select="title"/>
        </xsl:element>
        <xsl:element name="ul">
            <xsl:attribute name="class">syndication-list</xsl:attribute>
                <xsl:apply-templates select="item"/>
        </xsl:element>
    </xsl:template>
    <xsl:template match="/rss/channel/item">
        <xsl:element name="li">
            <xsl:attribute name="class">syndication-list-item</xsl:attribute>
            <xsl:element name="h2"><xsl:element name="a">
                <xsl:attribute name="href">
                    <xsl:value-of select="link"/>
                </xsl:attribute>
                <xsl:attribute name="title">
                    <xsl:value-of select="description"/>
                </xsl:attribute>
                <xsl:value-of select="title"/>
            </xsl:element></xsl:element>
            <xsl:if test="pubDate">
                <xsl:element name="div">
                    <xsl:attribute name="class">published</xsl:attribute>
                    Published: <xsl:value-of select="pubDate"/>
                </xsl:element>
            </xsl:if>
            <xsl:element name="div">
                <xsl:attribute name="class">entrydesc</xsl:attribute>
                <xsl:choose>
                    <xsl:when test="content:encoded">
                        <xsl:value-of select="content:encoded" disable-output-escaping="yes" />
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="description" disable-output-escaping="no" />
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:element>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

I could write code in Coldfusion to check what kind of feed is being process and then combine the feed with the appropriate stylesheet. This would let me have seperate XSLTs. However, because this is a feed tool I wanted one stylesheet to handle all types of feeds. Maybe this is mistake but I like the way it works thus far.

A side note – WordPress 2.0.x still uses Atom 0.3 as the standard for its Atom feed. However, there are some folks out there who have put together information on how to patch WordPress so that it has a functional Atom 1.0 feed. (Supposedly, Atom 1.0 support will come in WordPress 2.1) Check out these blog posts Enabling Atom 1.0 on WordPress, and Design the perfect Atom feed WordPress or this patch at another blog to fix your blog’s feed.

4 Responses leave one →
  1. 2006 August 27
    Bruce permalink

    Your templates are more complicated than they need to be. A lot of needless choose and element stuff.

    What I’d do is have template matches like “rss1:item|rss2:item|atom:item” and “rss1:title|rss2:title|atom:title” and then just end up with really simple templates like (not sure this will render):

    Easier to maintain and debug.

  2. 2006 August 27
    Bruce permalink

    Ack, the template was totally removed. What I wanted to show was that each template should just be a few lines, and that you don’t need the element and attribute elements. Just use the direct method of putting your expeted output there.

  3. 2009 November 10
    Vinod permalink

    where are the stylesheets that work for RSS 0.9, 1.0, and 2.0 and Atom 1.0 and 0.3

  4. 2009 November 10

    Check out this follow up post http://www.librarywebchic.net/wordpress/2006/09/22/feed-transform-revisited/. I think that this works with all the things you mention

Leave a Reply

Note: You can use basic XHTML in your comments. Your email address will never be published.

Subscribe to this comment feed via RSS