Use Nagare namespaces to create an rss feed
In Nagare HTML and XML generation is done through Renderers. Thus, to generate RSS feeds it is possible to use Nagare XML Renderer, which accept any tag or attribute. Another way is to create a RSS Renderer for Nagare which matches RSS namespace.
To do so we are extending Nagare XmlRender, which enforces possible xml tags and attributes (e.g. namespace).
Simple RSSRenderer
RSS specification, leads to the following namespace definition in Nagare:
class RssRenderer(xml.XmlRenderer):
"""RSS renderer"""
# RSS tags
# ------------
rss = TagProp('rss', set(('version', )))
channel = TagProp('channel', set())
title = TagProp('title', set())
link = TagProp('link', set())
description = TagProp('description', set())
language = TagProp('language', set())
copyright = TagProp('copyright', set())
managingEditor = TagProp('managingEditor', set())
webMaster = TagProp('webMaster', set())
pubDate = TagProp('pubDate', set())
lastBuildDate = TagProp('lastBuildDate', set())
category = TagProp('category', set())
generator = TagProp('generator', set())
docs = TagProp('docs', set())
cloud = TagProp('cloud', set(('domain', 'port',
'path', 'registerProcedure', 'protocol')))
ttl = TagProp('ttl', set())
image = TagProp('image', set())
url = TagProp('url', set())
width = TagProp('width', set())
height = TagProp('height', set())
rating = TagProp('rating', set())
textInput = TagProp('textInput', set())
name = TagProp('name', set())
skipHours = TagProp('skipHours', set())
skipDays = TagProp('skipDays', set())
item = TagProp('item', set())
title = TagProp('title', set())
link = TagProp('link', set())
description = TagProp('description', set())
author = TagProp('author', set())
category = TagProp('category', set(('domain', )))
comments = TagProp('comments', set())
enclosure = TagProp('enclosure', set(('url', 'length', 'type')))
guid = TagProp('guid', set(('isPermaLink', )))
pubDate = TagProp('pubDate', set())
source = TagProp('source', set(('url', )))
Note
Notes:
- RssRenderer checks if tags and attibutes exist in namespace
- RssRenderer does not validate against any DTD or schema
Let's look at the following example:
<?xml version="1.0"?>
<rss version="2.0">
<channel>
<title>Some Blog Title</title>
<link>http://someblog.example.com</link>
<description>Description</description>
<language>en-us</language>
<pubDate>Tue, 25 Jan 2010 14:00:00 GMT</pubDate>
<lastBuildDate>Tue, 25 Jan 2010 14:00:00 GMT</lastBuildDate>
<docs>http://blogs.law.harvard.edu/tech/rss</docs>
<generator>Some Generator</generator>
<managingEditor>editor@example.com</managingEditor>
<webMaster>webmaster@example.com</webMaster>
<item>
<title>Some Post Title</title>
<link>http://someblog.example.com/post1</link>
<description>Some Post Description</description>
<pubDate>Tue, 25 Jan 2010 14:00:00 GMT</pubDate>
<guid>Some Global Unique Identifier</guid>
</item>
</channel>
</rss>
With RssRenderer, this feed is generated this way:
r = rss.RssRenderer()
with r.rss(version="2.0"):
with r.channel:
r << r.title('Some Blog Title')
r << r.link('http://someblog.example.com')
r << r.description('Description')
r << r.language('en-us')
r << r.pubDate('Tue, 25 Jan 2010 14:00:00 GMT')
r << r.lastBuildDate('Tue, 25 Jan 2010 14:00:00 GMT')
r << r.docs('http://blogs.law.harvard.edu/tech/rss')
r << r.generator('Some Generator')
r << r.managingEditor('editor@example.com')
r << r.webMaster('webmaster@example.com')
with r.item:
r << r.title('Some Post Title')
r << r.link('http://someblog.example.com/post1')
r << r.description('Some Post Description')
r << r.pubDate('Tue, 25 Jan 2010 14:00:00 GMT')
r << r.guid('Some Global Unique Identifier')
Now RSSRenderer can be used to generate any RSS feed.
Mixing multiple namespaces
There's several extensions to RSS, actually extensions are just XML namespaces added in the feed. One simple extension is blogChannel namespace.
First create a BlogChannelRenderer:
class BlogChannelRenderer(xml.XmlRenderer):
blogRoll = TagProp('blogRoll', set())
mySubscriptions = TagProp('mySubscriptions', set())
blink = TagProp('blink', set())
changes = TagProp('changes', set())
Now we can mix RssRenderer and BlogChannelRenderer to create one feed:
r = rss.RssRenderer()
r.namespaces = {'blogChannel': 'http://backend.userland.com/blogChannelModule'}
b = rss.BlogChannelRenderer(r)
b.default_namespace = 'blogChannel'
with r.rss(version="2.0"):
with r.channel:
r << r.title('Some Blog Title')
r << r.link('http://someblog.example.com')
r << r.description('Description')
r << r.language('en-us')
r << b.blogRoll('http://someblog.example.com/blogroll')
r << b.mySubscriptions('http://someblog.example.com/subscriptions')
r << b.blink('http://someblog.example.com/backlink')
r << b.changes('http://someblog.example.com/changes')
r << r.pubDate('Tue, 25 Jan 2010 14:00:00 GMT')
r << r.lastBuildDate('Tue, 25 Jan 2010 14:00:00 GMT')
r << r.docs('http://blogs.law.harvard.edu/tech/rss')
r << r.generator('Some Generator')
r << r.managingEditor('editor@example.com')
r << r.webMaster('webmaster@example.com')
with r.item:
r << r.title('Some Post Title')
r << r.link('http://someblog.example.com/post1')
r << r.description('Some Post Description')
r << r.pubDate('Tue, 25 Jan 2010 14:00:00 GMT')
r << r.guid('Some Global Unique Identifier')
This produces the following RSS feed:
<rss xmlns:blogChannel="http://backend.userland.com/blogChannelModule" version="2.0">
<channel>
<title>Some Blog Title</title>
<link>http://someblog.example.com</link>
<description>Description</description>
<language>en-us</language>
<blogChannel:blogRoll>http://someblog.example.com/blogroll</blogChannel:blogRoll>
<blogChannel:mySubscriptions>http://someblog.example.com/subscriptions</blogChannel:mySubscriptions>
<blogChannel:blink>http://someblog.example.com/backlink</blogChannel:blink>
<blogChannel:changes>http://someblog.example.com/changes</blogChannel:changes>
<pubDate>Tue, 25 Jan 2010 14:00:00 GMT</pubDate>
<lastBuildDate>Tue, 25 Jan 2010 14:00:00 GMT</lastBuildDate>
<docs>http://blogs.law.harvard.edu/tech/rss</docs>
<generator>Some Generator</generator>
<managingEditor>editor@example.com</managingEditor>
<webMaster>webmaster@example.com</webMaster>
<item>
<title>Some Post Title</title>
<link>http://someblog.example.com/post1</link>
<description>Some Post Description</description>
<pubDate>Tue, 25 Jan 2010 14:00:00 GMT</pubDate>
<guid>Some Global Unique Identifier</guid>
</item>
</channel>
</rss>
With this process any XML namespace can be added to Nagare. For example, Nagare XHTML namespace is implemented as a Renderer.
Nagare installation on Mac OS X (Snow Leopard)
Snow Leopard has been released this summer.
The 64-bits Mac OS X version is installed by default on new Mac. Currently, the use of Nagare with the 64-bits stackless Mac OS X version leads to a Bus Error .
To get around this, we need to install a 32-bits stackless python, thus changing slightly the install procedure for Mac OS X described previously .
Install MacPorts
Install instructions here.
Configure MacPorts
MacPorts has to use universal variant (64 + 32 bits compilation).
In order to do so, you add +universal into variants.conf file, i.e. for default macports installation:
echo +universal | sudo tee -a /opt/local/etc/macports/variants.conf
Install Stackless
Now we have to run configure for 32-bits architecture:
cd /tmp
wget http://www.stackless.com/binaries/stackless-264-export.tar.bz2
tar jxvf stackless-264-export.tar.bz2
cd stackless-2.6.4*
CC="gcc -arch i386" ./configure --enable-stacklessfewerregisters --prefix=<STACKLESS_HOME>
make all
sudo make install
Once Stackless Python installed, Nagare installation goes on as usual.
rss