Get Suneido at SourceForge.net. Fast, secure and Free Open Source software downloads

(c) Suneido Software Corporation - Open Source Integrated Database and Programming Language

Support‎ > ‎Documents‎ > ‎

From the Couch 9 - An RSS 2 Feed Creator

I've been thinking for a while that we could use feeds as a way to "publish" data from our applications. In house, this could be things like error reports from our customers. For our customer applications, it could be used for things like reminders.

So I sat down with Developing Feeds with RSS and Atom and wrote some code to generate feeds. I picked RSS 2.0 since it looked like the simplest but similar code could be used for other standards.

A feed is simply an XML document so it's not too hard. I patterned the code after an example in the book of the Perl XML::RSS module.

Here's an example of how you use it:

rss = Rss2()
rss.Channel(title: 'My Channel',
    link: 'http://abc.com/mychannel.html',
    description: 'my channel of stuff')
rss.AddItem(title: 'My Item',
    description: 'my item of stuff')
Print(rss.ToString())

This would produce:

<?xml version="1.0" encoding="us-ascii"?>
<rss version="2.0">
<channel>
<title>My Channel</title>
<link>http://abc.com/mychannel.html</link>
<description>my channel of stuff</description>
<item>
<title>My Item</title>
<description>my item of stuff</description>
<guid>http://suneido.com/20071009_172526752</guid>
</item>
</channel>
</rss>

You can validate this using the W3C Feed Validator. The code checks for required elements.

Here is the code:

Rss2
class
{
New()
{
.items = []
}

channel: false
Channel(@args)
{
if .channel isnt false
throw "Rss2: only one channel allowed"
.channel = new .channel_element
.elements(.channel, args)
}
channel_element: class
{
Name: 'channel'
Elements: (title, link, description,
language, copyright, managingEditor, webMaster, pubDate,
lastBuildDate, category, generator, docs, cloud, ttl, image,
rating, textinput, skipDays, skipHours)
Required: (title, link, description)
}

image: false
Image(@args)
{
if .image isnt false
throw "Rss2: only one image allowed"
.image = new .image_element
if not args.Member?(#link) and .channel isnt false
args = args.Copy().Add(.channel.link, at: #link)
.elements(.image, args)
}
image_element: class
{
Name: 'image'
Elements: (url, title, link, width, height)
Required: (url, title, link)
}

textInput: false
TextInput(@args)
{
if .textInput isnt false
throw "Rss2: only one textInput allowed"
.textInput = new .textInput_element
.elements(.textInput, args)
}
textInput_element: class
{
Name: 'textInput'
Elements: (title, description, name, link)
Required: (title, description, name, link)
}

AddItem(@args)
{
.items.Add(item = new .item_element)
.elements(item, args)
if not item.Member?(#title) and not item.Member?(#description)
throw "Rss2: item must have either title or description"
}
item_element: class
{
Name: 'item'
Elements: (title, link, description, author, category,
comments, enclosure, guid, pubDate, source)
Required: ()
}

ToString()
{
return '<?xml version="1.0" encoding="us-ascii"?>\n' $
Xml('rss', version: '2.0')
{ '\n' $ .xml(.channel, .xml(.image) $ .xml(.textInput) $ .items_tostring()) }
}
items_tostring()
{
s = ''
for item in .items
{
if not item.Member?(#guid)
item.guid = .guid()
s $= .xml(item)
}
return s
}
guid()
{
return 'http://suneido.com/' $
Display(Timestamp()).Substr(1).Tr('.', '_')
}

elements(ob, args)
{
for m in args.Members()
if ob.Elements.Has?(m)
ob[m] = args[m]
else
throw 'Rss2: invalid element: ' $ ob.Name $ '/' $ m
for m in ob.Required
if not ob.Member?(m)
throw 'Rss2: missing element: ' $ ob.Name $ '/' $ m
}

xml(ob, body = '')
{
if ob is false
return ''
s = ''
for m in ob.Elements
if ob.Member?(m)
s $= Xml(m, XmlEntityEncode(ob[m])) $ '\n'
return Xml(ob.Name, '\n' $ s $ body) $ '\n'
}
}

The next step is to hook this up to HttpServer so you can actually access the feeds. And perhaps adding a caching mechanism so the feed doesn't have to be regenerated for every request.