quick search:
 

Create RSS Feed on the fly

Submitted by: rev_matt_y
Last Edited: 2003-12-23

Category: Python(Script)

Average rating is: 0.0 out of 5 (0 ratings)

Description:
This is a fairly simple (possibly more complex than it needs to be)
means of creating an RSS Feed on the fly.
This is aimed at CMF sites (may work on plone),
though it could probably be modified to work on non-CMF sites.


Source (Text):
from ZTUtils import LazyFilter,Batch
from Products.PythonScripts.standard import html_quote, structured_text
request = container.REQUEST
RESPONSE =  request.RESPONSE
site_title = context.portal_url.getPortalObject().Title()
site_desc = context.portal_url.getPortalObject().Description()
site_url = context.portal_url.getPortalObject().absolute_url()
#get last 5 blog entries
default_types = 'PABlog'
raw_items = context.contentValues(filter={'portal_type': default_types } )
sort_on = (('id', 'nocase', 'desc'),('id', 'cmp', 'desc'));
items = sequence.sort(raw_items, sort_on);
batch = Batch(items, 5, 0, orphan=1);
#create the rss file
print "<?xml version=\"1.0\"?>"
print "<!DOCTYPE rss PUBLIC \"-//Netscape Communications//DTD RSS 0.91//EN\" \"http://my.netscape.com/publish/formats/rss-0.91.dtd\">"
print "<rss version=\"0.91\">"
print "<channel>"
print "<title>%s</title>" % html_quote(site_title)
print "<link>%s</link>" % html_quote(site_url)
print "<description>%s</description>" % html_quote(site_desc)
print "<language>en-us</language>"

for i in batch:
     print "<item>"
     print "<title>%s</title>" % html_quote(i.title)
     print "<link>%s/blogentry_view</link>" % html_quote(i.absolute_url())
     print "<description>%s</description>" % structured_text(i.description)
     print "</item>"

print "</channel>"
return printed

Explanation:
You will need to include in your main template a line in the HEAD section like this:
<link rel="alternate" type="application/rss+xml" title="RSS" href="http://www.yourdomain.com/path.to.pythonscript"/>

This is obviously aimed at providing RSS for a PABlog based weblog,
you can change the content type in "default_types" line to 'Document'
or 'News Item' or whatever you want. If you do change it, also remove the
'/blogentry_view' in the link line.

The script is pretty self explanatory. Define the type of file you're
looking for, sort by most recent (blog entries use creation datetime as id)
grab the 5 most recent, print out well formed RSS.



UPDATED: to html_quote as recommended and to get the site title, description, and url automatically.


Comments:

Need to HTML escape the content by JimRoepcke - 2003-12-19
The contents of the fields need to be HTML escaped, for example the title and 
description tags.


Why not use the buildt in stuff? by raphael - 2003-12-22
In CMF there are (or have been?) some methods to support this already.
I use it for my newsfeed (only sightly customized) in the following way (yes, it is DTML because I could not figure out how to do this as ZPT)::

<?xml version="1.0"?>

<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
xmlns="http://purl.org/rss/1.0/"
>
<channel rdf:about="&dtml-portal_url;">
<title>&dtml-Title;</title>
<link>&dtml-portal_url;</link>
<description>
&dtml-Description;
</description>

<dtml-comment>
<image rdf:resource="logo.png" />
<sy:updatePeriod><dtml-var expr="portal_syndication.getUpdatePeriod(this())"></sy:updatePeriod>
<sy:updateFrequency><dtml-var expr="portal_syndication.getUpdateFrequency(this())"></sy:updateFrequency>
<sy:updateBase><dtml-var expr="portal_syndication.getHTML4UpdateBase(this())"></sy:updateBase>
</dtml-comment>

<dtml-comment>Start Items Elements</dtml-comment>
<items>
<rdf:Seq>

<dtml-in topNews size="10">
<rdf:li resource="<dtml-var getURL>" />
</dtml-in>
</rdf:Seq>
</items>
</channel>
<dtml-comment>End Items Elements</dtml-comment>

<dtml-comment>Start Item Elements</dtml-comment>

<dtml-in topNews size="10">
<dtml-let obj="_['sequence-item'].getObject()">
<dtml-var expr="itemRSS(obj)">
</dtml-let>
</dtml-in>
<dtml-comment>End Item Elements</dtml-comment>
</rdf:RDF>

The 'topNews' method queries the catalog for the recent news items.
'itemRSS' comes with CMFDefault and it is also included in Plone
(where it is in the 'cmf_legacy' skin folder)::

<item rdf:about="<dtml-var Identifier>">
<title><dtml-var Title></title>
<link><dtml-var Identifier></link>
<description>
<dtml-var Description>
</description>
<dc:publisher><dtml-var Publisher></dc:publisher>
<dc:creator><dtml-var Creator></dc:creator>
<dc:rights><dtml-var Rights></dc:rights>
<dtml-in Subject>
<dc:subject>
<dtml-var sequence-item>
</dc:subject>
</dtml-in>
<dc:date><dtml-var ModificationDate></dc:date>
</item>

Raphael


Why note use built-ins by rev_matt_y - 2003-12-23
I didn't use the CMF built-ins partially because this was tailored 
to the needs of Zope Product I developed (PABlog) and partially 
because the Python Script approach suits my needs better, being 
modular and marginally faster, and fulfills the rule of seperation.  

The DTML approach is cumbersome, and ZPT would be possible I'm 
sure but would take longer to develop and likely be less simple 
than the Python Script approach.

That being said, use what works best for your situation.  If the
 DTML or ZPT approach or the built-in suit your needs, then use 
them.  That's why there are many ways to do it ;)