|
|||||||||||||||||||||
|
|||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
What is it aboutIn the recent years, RSS has proved to be an extremely useful data-distribution technology. This article addresses the problem of handling different standards of RSS feeds in a single application. It can be useful for everyone who builds either one's own desktop aggregator or a corporate intranet environment. This article is accompanied with a skeleton of a newsreader application. This article assumes you're using MSXML 3.0+ as the XML/XSLT processor. StandardizationThe only sad thing about RSS is the number of standards in use. You cannot be sure what you'll get while surfing the net, so you must be ready for anything. "Anything" is:
Transform...Let's begin with the stylesheets. Three things are worth taking a note:
The first three stylesheets can be used to build a newspaper-style news feed: Listing 1.1: XSLT stylesheet for building newspaper-style HTML page from an RSS 2.0/0.91 feed<?xml version="1.0"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" version="1.0"
indent="yes" encoding="iso-8859-1"/>
<xsl:template match="/">
<html><body>
<div style=
"padding: 1em;background-color: #fafafa; border: 1px solid #cfcfcf;">
<xsl:for-each select="rss/channel/item">
<xsl:variable name="stl">
<xsl:text/>background-color: #efeff5;
border: 1px solid #cfcfcf;padding: 0em 1em 0em; margin:
<xsl:text/>
<xsl:choose>
<xsl:when test="position()=last()"> 0em</xsl:when>
<xsl:otherwise> 0em 0em 1em 0em</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<div>
<xsl:attribute name="style"><xsl:value-of select="$stl"/>
</xsl:attribute>
<p><h3 style="color:#800000"><xsl:value-of select="title"/></h3>
</p>
<p><xsl:value-of disable-output-escaping="yes"
select="description"/>
</p>
<xsl:variable name="pub" select="pubDate"/>
<xsl:if test="count($pub) > 0">
<p align="right"
style="margin:0; padding:0"><xsl:value-of select="pubDate"/>
</p>
</xsl:if>
<p style="margin:0; padding:0em 0em 1em 0em"><a target="_blank">
<xsl:attribute name="href">
<xsl:value-of select="link"/>
</xsl:attribute>
<xsl:value-of select="link"/>
</a></p>
</div>
</xsl:for-each>
</div>
</body></html>
</xsl:template>
</xsl:stylesheet>
Listing 1.2: XSLT stylesheet for building newspaper-style HTML page from an RSS 1.0 feed<?xml version="1.0"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html"
version="1.0" indent="yes" encoding="iso-8859-1"/>
<xsl:template match="/">
<html><body>
<div style=
"padding: 1em;background-color: #fafafa; border: 1px solid #cfcfcf;">
<xsl:for-each select="*/*[local-name()='item']">
<xsl:variable name="stl">
<xsl:text/>background-color: #efeff5;
border: 1px solid #cfcfcf;padding: 0em 1em 0em; margin:
<xsl:text/>
<xsl:choose>
<xsl:when test="position()=last()"> 0em</xsl:when>
<xsl:otherwise> 0em 0em 1em 0em</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<div>
<xsl:attribute name="style"><xsl:value-of select="$stl"/>
</xsl:attribute>
<p><h3 style="color:#800000">
<xsl:value-of select="./*[local-name()='title']"/>
</h3></p>
<p><xsl:value-of disable-output-escaping="yes"
select="./*[local-name()='description']"/>
<br/><br/>
<xsl:variable name="pub" select="*[local-name()='date']"/>
<xsl:variable name="pub_date"
select="concat(substring($pub, 0, 11), ', ',
substring($pub, 12, 8), ' (GMT+',
substring($pub, 21, 5), ')')"/>
<xsl:if test="count($pub) > 0">
<div align="right" style="margin:0em; padding:0em 0em 0em 0em;">
<xsl:value-of select="$pub_date"/></div>
</xsl:if>
<a target="_blank">
<xsl:attribute name="href">
<xsl:value-of select="./*[local-name()='link']"/>
</xsl:attribute><xsl:value-of select="./*[local-name()='link']"/>
</a></p>
</div>
</xsl:for-each>
</div>
</body></html>
</xsl:template>
</xsl:stylesheet>
Listing 1.3: XSLT stylesheet for building newspaper-style HTML page from an atom feed<?xml version="1.0"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html"
version="1.0" indent="yes" encoding="iso-8859-1"/>
<xsl:template match="/">
<html><body>
<div style=
"padding: 1em;background-color: #fafafa; border: 1px solid #cfcfcf;">
<xsl:for-each select="*/*[local-name()='entry']">
<xsl:variable name="stl">
<xsl:text/>
background-color: #efeff5;
border: 1px solid #cfcfcf;padding: 0em 1em 0em; margin:
<xsl:text/>
<xsl:choose>
<xsl:when test="position()=last()"> 0em</xsl:when>
<xsl:otherwise> 0em 0em 1em 0em</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<div>
<xsl:attribute name="style"><xsl:value-of select="$stl"/>
</xsl:attribute>
<p><h3 style="color:maroon">
<xsl:value-of select="*[local-name()='title']"/></h3></p>
<p><xsl:value-of disable-output-escaping="yes"
select="*[local-name()='summary']"/></p>
<xsl:variable name="pub" select="*[local-name()='updated']"/>
<xsl:variable name="pub_date" select=
"concat(substring($pub, 0, 11), ', ', substring($pub, 12, 8))"/>
<xsl:if test="count($pub)>0">
<p align="right" style="margin:0; padding:0;">
<xsl:value-of select="$pub_date"/>
</p>
</xsl:if>
<p style="margin:0; padding:0em 0em 1em 0em;"><a target="_blank">
<xsl:attribute name="href">
<xsl:value-of
select="*[local-name()='link']/@*[local-name()='href']"/>
</xsl:attribute>
<xsl:value-of
select="*[local-name()='link']/@*[local-name()='href']"/>
</a></p>
</div>
</xsl:for-each>
</div>
</body></html>
</xsl:template>
</xsl:stylesheet>
The next point of interest is the list of all the titles found in the feed - the outline. Each item in this list will be a link to a JavaScript "navTo" function, with a numeric argument equal to the item's position in the list. Listing 2.1: XSLT stylesheet for retrieving a list of items from an RSS 2.0/0.91 feed<?xml version="1.0"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html"
version="1.0" indent="yes" encoding="iso-8859-1"/>
<xsl:template match="/">
<html><body><ul style="margin-left:25">
<xsl:for-each select="rss/channel/item">
<li><a href="javascript:navTo('{position()}')">
<font style="size:-1;color:#800000">
<xsl:value-of select="title"/>
</font>
</a><br/></li>
</xsl:for-each>
</ul></body></html>
</xsl:template>
</xsl:stylesheet>
Listing 2.2: XSLT stylesheet for retrieving a list of items from an RSS 1.0 feed<?xml version="1.0"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" version="1.0"
indent="yes" encoding="iso-8859-1"/>
<xsl:template match="/">
<html><body><ul style="margin-left:25">
<xsl:for-each select="*/*[local-name()='item']">
<li><a href="javascript:navTo('{position()}')">
<font style="size:-1;color:#800000">
<xsl:value-of select="./*[local-name()='title']/text()"/>
</font>
</a><br/></li>
</xsl:for-each>
</ul></body></html>
</xsl:template>
</xsl:stylesheet>
Listing 2.3: XSLT stylesheet for retrieving a list of items from an atom feed<?xml version="1.0"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html"
version="1.0" indent="yes" encoding="iso-8859-1"/>
<xsl:template match="/">
<html><body><ul style="margin-left:25">
<xsl:for-each select="*/*[local-name()='entry']">
<li><a href="javascript:navTo('{position()}')">
<font style="size:-1;color:#800000">
<xsl:value-of select="./*[local-name()='title']/text()"/>
</font>
</a><br/></li>
</xsl:for-each>
</ul></body></html>
</xsl:template>
</xsl:stylesheet>
The last set of stylesheets do the job of transforming a single news item. Please take a note that these transformations cannot be applied to the original RSS file; prior to using them, you must programmatically extract the required item and apply one of the stylesheets to it. Listing 3.1: XSLT stylesheet for representing a distinct news item from an RSS 2.0/0.91 feed<?xml version="1.0"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html"
version="1.0" indent="yes" encoding="iso-8859-1"/>
<xsl:template match="*">
<div style="padding: 0em 1em 0em;
background-color: #fafafa; border: 1px solid #cfcfcf;">
<p><h3 style="color:#800000"><xsl:value-of select="title"/></h3></p>
<div style="padding: 0em 1em 0em; margin: 0em;
background-color: #efeff5; border: 1px solid #cfcfcf;">
<p><xsl:value-of disable-output-escaping="yes" select="description"/>
</p>
<xsl:variable name="pub" select="pubDate"/>
<xsl:if test="count($pub)>0">
<p align="right" style="margin:0em; padding:0em 0em 1em 0em;">
<xsl:value-of select="pubDate"/></p>
</xsl:if>
</div>
<p><a target="_blank">
<xsl:attribute name="href">
<xsl:value-of select="link"/>
</xsl:attribute>
<xsl:value-of select="link"/>
</a></p>
</div>
</xsl:template>
</xsl:stylesheet>
Listing 3.2: XSLT stylesheet for representing a distinct news item from an RSS 1.0 feed<?xml version="1.0"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html"
version="1.0" indent="yes" encoding="iso-8859-1"/>
<xsl:template match="*">
<div style="padding: 0em 1em 0em;
background-color: #fafafa; border: 1px solid #cfcfcf;">
<p><h3 style="color:#800000">
<xsl:value-of select="./*[local-name()='title']"/>
</h3></p>
<div style="padding: 0em 1em 0em; margin: 0em;
background-color: #efeff5; border: 1px solid #cfcfcf;">
<p><xsl:value-of disable-output-escaping="yes"
select="./*[local-name()='description']"/></p>
<xsl:variable name="pub" select="*[local-name()='date']"/>
<xsl:variable name="pub_date"
select="concat(substring($pub, 0, 11), ', ',
substring($pub, 12, 8),
' (GMT+', substring($pub, 21, 5), ')')"/>
<xsl:if test="count($pub) > 0">
<p align="right" style="margin:0em; padding:0em 0em 1em 0em;">
<xsl:value-of select="$pub_date"/>
</p>
</xsl:if>
</div>
<p><a target="_blank">
<xsl:attribute name="href">
<xsl:value-of select="./*[local-name()='link']"/>
</xsl:attribute><xsl:value-of select="./*[local-name()='link']"/>
</a></p>
</div>
</xsl:template>
</xsl:stylesheet>
Listing 3.3: XSLT stylesheet for representing a distinct news item from an atom feed<?xml version="1.0"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html"
version="1.0" indent="yes" encoding="iso-8859-1"/>
<xsl:template match="*">
<div style="padding: 0em 1em 0em;
background-color: #fafafa; border: 1px solid #cfcfcf;">
<p><h3 style="color:#800000">
<xsl:value-of select="*[local-name()='title']"/>
</h3></p>
<xsl:variable name="cnt" select="*[local-name()='content']">
</xsl:variable>
<xsl:if test="count($cnt)>0">
<div style="padding: 0em 1em 0em 1em; margin: 0em;
background-color: #efeff5; border: 1px solid #cfcfcf;">
<p><xsl:value-of disable-output-escaping="yes"
select="*[local-name()='content']"/></p>
<xsl:variable name="pub" select="*[local-name()='updated']"/>
<xsl:variable name="pub_date"
select="concat(substring($pub, 0, 11), ', ',
substring($pub, 12, 8))"/>
<xsl:if test="count($pub)>0">
<p align="right" style="margin:0em; padding:0em 0em 1em 0em;">
<xsl:value-of select="$pub_date"/>
</p>
</xsl:if>
</div>
</xsl:if>
<xsl:if test="count($cnt)=0">
<p style="padding: 1em; margin: 0em;
background-color: #efeff5; border: 1px solid #cfcfcf;">
<xsl:value-of disable-output-escaping="yes"
select="*[local-name()='summary']"/>
</p>
</xsl:if>
<p><a target="_blank">
<xsl:attribute name="href">
<xsl:value-of
select="*[local-name()='link']/@*[local-name()='href']"/>
</xsl:attribute>
<xsl:value-of
select="*[local-name()='link']/@*[local-name()='href']"/>
</a></p>
</div>
</xsl:template>
</xsl:stylesheet>
...and readBefore doing anything to an RSS file, you need to know the standard it belongs to, right? We do this by analyzing the child node of Listing 4.1: Extracting the RSS standardfunction whatStd(rssdocument)
{
var rssroot =
rssdocument.documentElement.selectSingleNode("/*");
var rsssdtd = rssroot.baseName;
switch(rsssdtd)
{
case "rss":
return "rss2";
case "RDF":
return "rss1";
case "feed":
return "atom";
default:
return "";
}
}
The bad thing about this (and all the following) code is that it heavily uses Microsoft extensions to W3C's XML API. As a solution you can simply extract the Listing 4.2: Extracting RSS channel infovar rss_title;
switch(standard)
{
case "atom":
rss_title = xml.documentElement.selectSingleNode(
"/*/*[local-name()='title']");
break;
case "rss1":
rss_title = xml.documentElement.selectSingleNode(
"/*/*[local-name()='channel']/*[local-name()='title']");
break;
case "rss2":
rss_title = xml.documentElement.selectSingleNode(
"/*/channel/title");
break;
}
var rss_link;
switch(standard)
{
case "atom":
rss_link = xml.documentElement.selectSingleNode(
"/*/*[local-name()='link']/@*[local-name()='href']");
break;
case "rss1":
rss_link = xml.documentElement.selectSingleNode(
"/*/*[local-name()='channel']/*[local-name()='link']");
break;
case "rss2":
rss_link = xml.documentElement.selectSingleNode(
"/*/channel/link");
break;
}
rsstitle.innerHTML =
"<a target=\"_blank\" title=\"Opens in new window\" href=\"" +
rss_link.text +
"\"><font color=\"maroon\" size=\"4\"><b>" +
rss_title.text + "</b></font></a>";
Having extracted a channel info, it'll be very easy to extract a single item from the feed. Here we go. Listing 4.3: Extracting the news itemfunction navTo(where)
{
if(rssFile != "")
{
var rss_item;
switch(standard)
{
case "atom":
rss_item = xml.documentElement.selectSingleNode(
"/*/*[local-name()='entry'][" + where + "]");
break;
case "rss1":
rss_item = xml.documentElement.selectSingleNode(
"/*/*[local-name()='item'][" + where + "]");
break;
case "rss2":
rss_item = xml.documentElement.selectSingleNode(
"/*/channel/item[" + where + "]");
break;
default:
rss_item = null;
}
if(rss_item)
{
var item_i =
rss_item.transformNode(xsl_i.documentElement);
contentcell.vAlign = "Top";
content.innerHTML = item_i;
...
}
}
}
Take a note of the That's all. Feel free to e-mail me all your suggestions/opinions/bug reports. LinksTutorials
RSS lists
Tools and everything else
History
| ||||||||||||||||||||