# Blosxom Plugin: rss20
# Author(s): Gavin Carr <gavin@openfusion.com.au>
-# Version: 0.001000
-# Requires: lastmodified2
+# Version: 0.001002
+# Requires: storydate, lastmodified2
# Suggests: absolute
-# Follows: lastmodified2
+# Follows: storydate, lastmodified2
package rss20;
# Generator that produced this feed
$generator_url = "http://blosxom.sourceforge.net/?v=$blosxom::version";
-# Debug verbosity
-my $debug_level = 0;
-
# --------------------------------
$error_email ||= $author_email;
+# Escape <, >, and & to hex-encoded entities for max compatibility in text elements
+# See http://www.rssboard.org/rss-profile#data-types-characterdata
+my %escape_text = (
+ '<' => '<',
+ '>' => '>',
+ '&' => '&',
+);
+my $escape_text_re = join '|' => keys %escape_text;
+
+# Escape <, >, and & to standard html-encoded entities for in html elements
+my %escape_html = (
+ '<' => '<',
+ '>' => '>',
+ '&' => '&',
+);
+my $escape_html_re = join '|' => keys %escape_html;
+
sub start {
_load_templates();
+}
- 1;
+sub story {
+ my ($pkg, $path, $filename, $story_ref, $title_ref, $body_ref) = @_;
+
+ # Ignore flavours other than ours
+ return unless $blosxom::flavour eq $flavour;
+
+ # Don't double-encode if someone else has already done it
+ return unless $blosxom::encode_xml_entities;
+
+ # Encode and reset encode_xml_entities flag
+ $$title_ref = _escape_text( $$title_ref );
+ $$body_ref = _escape_html( $$body_ref );
+ $blosxom::encode_xml_entities = 0;
}
# --- Private subroutines
+sub _escape_text {
+ my ($text) = @_;
+ $text =~ s/($escape_text_re)/$escape_text{$1}/g;
+ return $text;
+}
+
+sub _escape_html {
+ my ($html) = @_;
+ $html =~ s/($escape_html_re)/$escape_html{$1}/g;
+ return $html;
+}
+
sub _load_templates {
- $blosxom::template{$flavour}{'content_type'} = 'text/xml';
+ $blosxom::template{$flavour}{'content_type'} = 'text/xml; charset=$blog_encoding';
$blosxom::template{$flavour}{'date'} = "\n";
- $blosxom::template{$flavour}{'head'} = <<'HEAD';
-<?xml version="1.0" encoding="iso-8859-1"?>
+ $blosxom::template{$flavour}{'head'} = <<HEAD;
+<?xml version="1.0" encoding="$blosxom::blog_encoding"?>
<rss version="2.0"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
xmlns:admin="http://webns.net/mvcb/"
+ xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
- <title>$blog_title</title>
- <link>$url</link>
- <description>$blog_description</description>
- <dc:date>$lastmodified2::latest_iso8601</dc:date>
+ <title>$blosxom::blog_title</title>
+ <link>$blosxom::url</link>
+ <description>$blosxom::blog_description</description>
+ <dc:date>\$lastmodified2::latest_iso8601</dc:date>
<dc:language>$blosxom::blog_language</dc:language>
<dc:creator>mailto:$rss20::author_email</dc:creator>
<dc:rights>$rss20::copyright</dc:rights>
<admin:generatorAgent rdf:resource="$rss20::generator_url" />
<admin:errorReportsTo rdf:resource="mailto:$rss20::error_email" />
+ <atom:link href="$blosxom::url$ENV{PATH_INFO}" rel="self" type="application/rss+xml" />
<sy:updatePeriod>hourly</sy:updatePeriod>
<sy:updateFrequency>1</sy:updateFrequency>
<sy:updateBase>2000-01-01T12:00+00:00</sy:updateBase>
<description>\$body</description>
<comments>$rss20::trackback_link</comments>
<guid isPermaLink="true">$rss20::permalink</guid>
- <dc:date>\$lastmodified2::story_iso8601</dc:date>
+ <dc:date>\$storydate::story_iso8601</dc:date>
</item>
STORY
</channel>
</rss>
FOOT
+
+ 1;
}