Thursday, March 6, 2008

Transforming feeds...one XSLT to rule them all

For a client at my work I needed to built a feed reading module in to their CMS. I created the following XSLT to transform the feeds to the desired HTML. This XSLT can be used for Atom 0.3, Atom 1.0, RSS 0.90, RSS 0.91, RSS 0.92, RSS 1.0 and RSS 2.0.

With some minor tweaks this can be used in Umbraco as well. Here is an example of reading a atom feed in Umbraco.


Here is my XSLT.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:atom="http://www.w3.org/2005/Atom"
    xmlns:atom3="http://purl.org/atom/ns#"
    xmlns:rss="http://purl.org/rss/1.0/"
    xmlns:rss09="http://my.netscape.com/rdf/simple/0.9/"    
    exclude-result-prefixes="xsl rdf dc rss rss09 atom atom3"
>

<!--
=============================================================================
 XSLT to convert RSS and Atom feeds to desired html
=============================================================================
-->
<xsl:output method="html" omit-xml-declaration="yes" indent="yes"/>

<!--
=============================================================================
Input parameters for displaying maximum items from feed
=============================================================================
-->

<xsl:variable name="maxitems" select="10" />

<xsl:template match="/">
                
    <xsl:element name="ul">    
        <xsl:attribute name="class">rssfeed</xsl:attribute>        
        
        <!-- Atom 1.0 -->
        <xsl:apply-templates select="/atom:feed"/>
        <!-- Atom 0.3 -->
        <xsl:apply-templates select="/atom3:feed"/>
        <!-- RSS 0.91 , 0.92 , 2.0 -->
        <xsl:apply-templates select="rss/channel" />
        <!-- RSS 1.0 -->
        <xsl:if test="rdf:RDF/rss:item">
            <xsl:apply-templates select="rdf:RDF/rss:item[position() &lt; number($maxitems)+1]"/>
        </xsl:if>
        <!-- RSS 0.9 -->
        <xsl:if test="rdf:RDF/rss09:item">
            <xsl:apply-templates select="rdf:RDF/rss09:item[position() &lt; number($maxitems)+1]"/>
        </xsl:if>
        
    </xsl:element>

</xsl:template>


<!--
=============================================================================
 RSS 0.91,0.92,2.0
=============================================================================
-->
<xsl:template match="channel">        
    <xsl:apply-templates select="item[position() &lt; number($maxitems)+1]" />        
</xsl:template>

<xsl:template match="item">       
    <xsl:call-template name="drawlinks">
        <xsl:with-param name="item_link" select="link" />
        <xsl:with-param name="item_title" select="title" />
    </xsl:call-template>
</xsl:template>


<!--
=============================================================================
 RSS 1.0
=============================================================================
-->
<xsl:template match="rss:item">     
     <xsl:call-template name="drawlinks">
        <xsl:with-param name="item_link" select="rss:link" />
        <xsl:with-param name="item_title" select="rss:title" />
    </xsl:call-template>
</xsl:template>

<!--
=============================================================================
 RSS 0.90
=============================================================================
-->
<xsl:template match="rss09:item">    
    <xsl:call-template name="drawlinks">
        <xsl:with-param name="item_link" select="rss09:link" />
        <xsl:with-param name="item_title" select="rss09:title" />
    </xsl:call-template>
</xsl:template>

<!--
=============================================================================
Atom 1.0
=============================================================================
-->
<xsl:template match="/atom:feed">
    <xsl:apply-templates select="atom:entry[position() &lt; number($maxitems)+1]" />
</xsl:template>

<xsl:template match="atom:entry">
    <xsl:call-template name="drawlinks">
        <xsl:with-param name="item_link" select="atom:link/@href" />
        <xsl:with-param name="item_title" select="atom:title" />
    </xsl:call-template>
</xsl:template> 

<!--
=============================================================================
Atom 0.3
=============================================================================
--> 
<xsl:template match="/atom3:feed">    
    <xsl:apply-templates select="atom3:entry[position() &lt; number($maxitems)+1]" />    
</xsl:template>
 
<xsl:template match="atom3:entry">  
    <xsl:call-template name="drawlinks">
        <xsl:with-param name="item_link" select="atom3:link/@href" />
        <xsl:with-param name="item_title" select="atom3:title" />
    </xsl:call-template>
</xsl:template> 

<!--
=============================================================================
Template for making list items from feed items
=============================================================================
-->
<xsl:template name="drawlinks">
    <xsl:param name="item_link" />
    <xsl:param name="item_title" />
    <xsl:element name="li">        
        <xsl:element name="a">
            <xsl:attribute name="href"><xsl:value-of select="$item_link" /></xsl:attribute>
            <xsl:attribute name="target">_blank</xsl:attribute>
            <xsl:attribute name="title"><xsl:value-of select="$item_title" /></xsl:attribute>
            <xsl:value-of select="$item_title" />
        </xsl:element>    
    </xsl:element>
</xsl:template>
</xsl:stylesheet>

If you have issues with this, let me know.

Cheers,

Dave

8 comments:

bangontarget said...

Thank you so much for this excellent guide. It saved me days and headache.

Anonymous said...

Thank you very much for posting this. It was exactly what I was looking for!

Unknown said...

Hi,

Seems perfect for my needs.

I cant find the reference to the umbraco link anymore.

Can you help me converting your xslt code to umbraco?

Where do i add the feed url in your example?

Dave W said...

Hey Peter,

Maybe this page can put you on the way :
http://our.umbraco.org/wiki/how-tos/xslt-useful-tips-and-snippets/reading-rss-feeds,-aggregating-and-sorting

Unknown said...

Hi Dave,

Thanks, i found out how to do it.

Unknown said...

Hi,

An updated version of your code for use in Umbraco is posted here:
http://our.umbraco.org/wiki/how-tos/xslt-useful-tips-and-snippets/xslt-handling-of-all-rss-versions

greg.obyrne said...

Just so you know. That is a brilliant little piece of XSLT that I just used right now in 2015!

Check it out here:
http://backbyrner.com/post/New-Widget-for-BlogEngineNet-RSS-Reader-Plus

Thanks,
g

lolyboy007 said...

Can you please help me here? I just want to reverse the process and I dont understand how to do it with atom? Actually I want to have XML type of atom feed with XSLT. But the problem is I am not converting it from Atom but trying to make Atom from my news page. can you please give me suggestion or example for it

Thanks in advance