In order to ease the edition of RSS feeds, I've written this tiny perl program with it's Tk graphical user interface in order to be as platform independent as possible (Windows, Linux, Unix or Mac-OS X). It's pretty basic but can be used as a seed for something more elaborate. It's just a proof of concept.

#! /usr/bin/perl-w # PerlTk RSS Feed Editor # Creative commons, habett, 2005
I've maximized explicitly the use of modules but really XML::RSS is the only one that isn't included in a standard ActivePerl distribution.
use Tk; use Tk::widgets qw(TextUndo Scrollbar LabEntry NoteBook); use XML::RSS; use strict; use Carp; use diagnostics; use locale;
First we create an RSS feed object with the encoding forced to ISO 8859-1 to ease things up. We read the empty feed, load and parse with the appropriate sub.
# blank feed reading my $rss = new XML::RSS(encoding=>"ISO-8859-1"); my $file="blank.xml"; readfeed($file);
Next we construct the graphical user interface with Tk widgets. Hence the use of textvariable for linking some widgets.
# creation of the main window
my $mainwindow = MainWindow->new();
$mainwindow->configure(-title => "Daal, EdRSS");
$mainwindow->optionAdd('*TextUndo.Background' => '#fff5e1');
my $z="#";
$mainwindow->Button(-text => 'Open a feed',-width=>80,
-command => \&loadfeed)->pack(-side=>"top",-anchor=>"n",-fill=>'x',-padx=>10,-pady=>10);
# General information
my $title = $mainwindow->LabEntry(-label=>"Title",-labelPack=>[-anchor=>"n"],-width=>80,
-textvariable=>$rss->channel("title"))->pack(-side=>"top",-anchor=>"nw",-padx =>10,-pady=>10);
my $description = $mainwindow->LabEntry(-label=>"Description",-labelPack =>[-anchor=>"n"],-width=>80,
-textvariable=>$rss->channel("description"))->pack(-side=>"top",-anchor=>"nw",-padx=>10,-pady=>10);
my $link = $mainwindow->LabEntry(-label=>"URL",-labelPack=>[-anchor=>"n"],-width=>80,
-textvariable=>$rss->channel("link"))->pack(-side=>"top",-anchor=>"nw",-padx=>10,-pady=>10);
# ne item creator
$mainwindow->Button(-text=>'New entry',-width=>80,-foreground=>'blue',
-command => \&nouvelle)->pack(-side=>"top",-anchor=>"n",-fill=>'x',-padx=>10,-pady=>10);
Next we use the NoteBook widget to symbolize the items of the feed. As we'll see in time, we try to keep 15 items as seems to be the regular standard.
# NoteBook for the feed's entries my $w_book = $mainwindow->NoteBook()->pack(-padx=>10,-pady=>10); my (@text,@w_page); &book; # quit and or save $mainwindow->Button(-text=>'Quit without saving',-width=>80,-relief=>'sunken',-foreground=>'red', -command=> \&quit)->pack(-anchor=>"s",-fill=>'x',-padx=>10,-pady=>10); $mainwindow->Button(-text=>'Save and quit',-width=>80,-foreground=>'darkgreen', -command=>\&saveclose)->pack(-anchor=>"s",-fill=>'x',-padx=>10,-pady=>10);
Once we've got the interface, we can launch the process and prepare a clean closing.
MainLoop(); exit(0);
Now to the subs : the first one adds an entry to the feed and deletes one if we've reach the 15 limit. Once processed, the feed's display is updated by the &book; sub.
sub nouvelle {
# new feed item
$rss->channel(title=>$title->get,link=>$link->get,description=>$description->get,lastBuildDate=>&tome);
my $i = 0;
foreach my $item (@{$rss->{'items'}}) {
$i++;
$item->{'title'}=$item->{'title'}->get;
$item->{'link'}=$item->{'link'}->get;
$item->{'description'}=$text[$i]->Contents;
}
pop(@{$rss->{'items'}}) if (@{$rss->{'items'}} == 15);
$rss->add_item(title=>'Newu',link=>"http://",pubDate=>&tome,mode=>'insert');
$rss->save($file);
&book;
}
Creation of an adaptated open file dialog.
sub loadfeed {
# looking for .xml or .rss files in order to load them
my @types = (["Feeds", ['.xml','.rss']],["All Files", "*"] );
$file = $mainwindow->getOpenFile(-filetypes => \@types);
&readfeed;
&book;
}
Display the new feed after cleanning the NoteBook.
sub book {
# clean the notebook
my @totej = $w_book->pages;
foreach(@totej) {
$w_book->delete($_);
}
# recreate the notebook
my $i = 0;
&readfeed ($file);
foreach my $item (@{$rss-gt;{'items'}}) {
$i++;
$w_page[$i] = $w_book->add("$i",-label=>"$z$i");
$item->{'title'} = $w_page[$i]->Entry(-relief=>'sunken',-width=>80,-textvariable=>$item->{'title'})->pack;
$item->{'link'} = $w_page[$i]->Entry(-relief=>'sunken',-width=>80,-textvariable=>$item->{'link'})->pack;
$text[$i] = $w_page[$i]->TextUndo(-relief=>'sunken',-width=>69,-height=>4,-wrap=>'word')->pack;
$text[$i]->Insert($item->{'description'});
$text[$i]->focus;
$w_page[$i]->pack;
}
# update meta informations
$title->delete(0,"end");
$title->insert("end",$rss->channel('title'));
$link->delete(0,"end");
$link->insert("end",$rss->channel('link'));
$description->delete(0,"end");
$description->insert("end",$rss->channel('description'));
}
And the, as usual, read, save and quit.
sub readfeed {
# read and parse the feed
my $file = shift;
return unless $file;
return unless -e $file;
my $textfile;
open (IN, $file);
$textfile .= $_ while ();
close (IN);
$rss->parse($textfile);
}
sub saveclose {
# save the feed
$rss->channel(title=>$title->get,link=>$link->get,description=>$description->get);
my $i=0;
foreach my$item (@{$rss->{'items'}}) {
$i++;
$item->{'title'}=$item->{'title'}->get;
$item->{'link'}=$item->{'link'}->get;
my $temp=$text[$i]->Contents;
chomp($temp);
$item->{'description'}=$temp;
}
$rss->save($file);
# and quit
exit;
}
sub quit {
exit(0);
}
To adapt the date time format to the usual standard, hence the small gmtime tweaking.
sub tome {
my ($wday,$month,$dayn,$time,$year) = split(/ +/,scalar gmtime);
return "$wday, $dayn $month $year $time GMT";
}
That's all folks. The code could be more modularized but it's functionnal. Thanks to XML::RSS, it's agnostic to feed formats and versions so it's neat.