Transforming RSS and Atom feeds
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.
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.
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.
where are the stylesheets that work for RSS 0.9, 1.0, and 2.0 and Atom 1.0 and 0.3
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