June 18, 2003

Making Feature-Rich, Movable Type RSS Files

by Ben Hammersley, author of Content Syndication with RSS 02/28/2003

The curse of metadata, once you get over the intractable issues of trust and standards and categorization, is that you never know how much to give. For the weblogging community, which produces masses of metadata, mostly without knowing it, this is especially true: we could be giving out so much more for others to play with, and with very little effort.

Take the default RSS 1.0 template within Movable Type. It looks like this:

<?xml version="1.0" encoding="<$MTPublishCharset$>"?>

<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:admin="http://webns.net/mvcb/"
   xmlns:cc="http://web.resource.org/cc/"
   xmlns="http://purl.org/rss/1.0/">

  <channel rdf:about="<$MTBlogURL$>">
    <title><$MTBlogName encode_xml="1"$></title>
    <link><$MTBlogURL$></link>
    <description><$MTBlogDescription encode_xml="1"$></description>
    <dc:language>en-us</dc:language>
    <dc:creator></dc:creator>
    <dc:date><MTEntries lastn="1"><$MTEntryDate format="%Y-%m-%dT%H:%M:%S" 
       language="en"$><$MTBlogTimezone$></MTEntries></dc:date>
    <admin:generatorAgent 
       rdf:resource="http://www.movabletype.org/?v=<$MTVersion$>" />
    <MTBlogIfCCLicense>
       <cc:license rdf:resource="<$MTBlogCCLicenseURL$>" />
    </MTBlogIfCCLicense>

    <items>
       <rdf:Seq><MTEntries lastn="15">
          <rdf:li rdf:resource="<$MTEntryPermalink encode_xml="1"$>" />
       </MTEntries></rdf:Seq>
    </items>

  </channel>

  <MTEntries lastn="15">
    <item rdf:about="<$MTEntryPermalink encode_xml="1"$>">
      <title><$MTEntryTitle encode_xml="1"$></title>
      <link><$MTEntryPermalink encode_xml="1"$></link>
      <description><$MTEntryExcerpt encode_xml="1"$></description>
      <dc:subject><$MTEntryCategory encode_xml="1"$></dc:subject>
      <dc:creator><$MTEntryAuthor encode_xml="1"$></dc:creator>
      <dc:date><$MTEntryDate format="%Y-%m-%dT%H:%M:%S" 
         language="en"$><$MTBlogTimezone$></dc:date>
    </item>
  </MTEntries>

</rdf:RDF>

This template works well, but it doesn't include all the information it could. RSS (especially RSS 1.0) feeds are made much more valuable with every extra piece of information we can put inside of them. The default template already uses the Dublin Core module, which allows us to point out subject and date and so on, but it doesn't go to the extremes that any self-respecting RSS provider would like.

So, let's look at the feed one section at a time, and add in what we can. First, the <channel> information: we're already giving quite a considerable amount of information here, and there is really only one element left to add in, the <admin:errorReportsTo>.

This element holds your email address, so if someone using your feed finds something terribly wrong with it, they can contact you. With my own email address, I add this line to the template:

<admin:errorReportsTo rdf:resource="mailto:ben@benhammersley.com"/>

You'll want to use your own email address. Moving on, we get to the <item>s. In weblog RSS feeds, each <item> contains information about a single weblog entry. There is a lot to say about weblog entries in Movable Type. We're already giving information about the author, the creation date, and the category, but RSS 1.0 allows for much more.

If we're allowing comments on the entry, the <annotate:reference> element can point to the URL of the page where people can have their say, and the <dc:contributor> element can hold details of anyone who has left a comment. In this way, aggregators that recognize this field, such as NewsMonster, can display a list of commentators, and perhaps provide aggregation based on items where your friends have left comments.

Of course, you might turn off commenting for some entries, so we must wrap the entire section of the template in an <MTEntryIfAllowComments> tag.

<MTEntryIfAllowComments>
  <annotate:reference rdf:resource="<$MTEntryPermalink encode_xml="1"$>" />
  <MTComments>
    <dc:contributor>
      <foaf:person foaf:name="<MTCommentAuthor encode_xml="1">">
        <foaf:homepage rdf:resource="<MTCommentURL encode_xml="1">" />
        <foaf:email rdf:resource="<$MTCommentEmail encode_xml="1"$>" />
      </foaf:person>
    </dc:contributor>
  </MTComments>
</MTEntryIfAllowComments>

You'll notice that we're providing details of the commentator inside of FOAF elements. FOAF, or Friend of a Friend, is an RDF vocabulary that gives us lots of scope for describing people. For more on that, see rdfweb.org.

Next up for Movable Type feeds comes details of TrackBacking. TrackBack is Movable Type's two-way linking system, which allows entries to refer to, and be referred to by, other posts on other weblogs, with the weblogging systems informing each other of the link.

As TrackBacking goes both ways, this is a great bit of metadata to include in one's feed. This template section here uses the TrackBack RSS 1.0 module by Justin Klubnik to detail which TrackBack pings have been sent from the entry in question.

<MTPingsSent>
  <trackback:about rdf:resource="<$MTPingsSentURL encode_xml="1"$>"/>
</MTPingsSent>

And this template snippet deals with which pings have been received by the entry in question, detailed with the <dcterms:isReferencedBy> element, checking first to see if TrackBacking that entry has been allowed, and if so, detailing the URL to ping to trackback to that entry as well.

<MTEntryIfAllowPings>
  <trackback:ping rdf:resource="<MTEntryTrackbackLink encode_xml="1">"/>
  <MTPings>
    <dcterms:isReferencedBy rdf:resource="<$MTPingURL encode_xml="1"$>" />
  </MTPings>
</MTEntryIfAllowPings>

So now we have a feed that contains all of the data we can pull out of a standard Movable Type installation. For totally standards-compliant newsreaders, much of this detail could be displayed very easily, and the rest of it can be used for more advanced RDF applications. That there are few of these right now is not an excuse, of course: the 30 seconds it takes to replace the default template with the complete one below is a small investment to make when the data produced might allow for a new generation of RDF applications.

<?xml version="1.0" encoding="<$MTPublishCharset$>"?>

<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/"
  xmlns:admin="http://webns.net/mvcb/"
  xmlns:annotate="http://purl.org/rss/1.0/modules/annotate/"
  xmlns:dcterms="http://purl.org/dc/terms/"
  xmlns:cc="http://web.resource.org/cc/"
  xmlns:content="http://purl.org/rss/1.0/modules/content/"
  xmlns:foaf="http://xmlns.com/foaf/0.1/"
  xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"
 >

  <channel rdf:about="<$MTBlogURL$>">
    <title><$MTBlogName encode_xml="1"$></title>
    <link><$MTBlogURL$></link>
    <description><$MTBlogDescription encode_xml="1"$></description>
    <dc:language>en-us</dc:language>
    <dc:creator>Your Name Here</dc:creator>
    <dc:date><MTEntries lastn="1"><$MTEntryDate format="%Y-%m-%dT%H:%M:%S" 
       language="en"$><$MTBlogTimezone$></MTEntries></dc:date>
    <admin:generatorAgent 
        rdf:resource="http://www.movabletype.org/?v=<$MTVersion$>" />
    <admin:errorReportsTo rdf:resource="mailto:your email here"/>

    <MTBlogIfCCLicense>
      <cc:license rdf:resource="<$MTBlogCCLicenseURL$>" />
    </MTBlogIfCCLicense>

    <items>
      <rdf:Seq><MTEntries lastn="15">
        <rdf:li rdf:resource="<$MTEntryPermalink encode_xml="1"$>" />
      </MTEntries></rdf:Seq>
    </items>

  </channel>

  <MTEntries lastn="15">
    <item rdf:about="<$MTEntryPermalink encode_xml="1"$>">
    <title><$MTEntryTitle encode_xml="1"$></title>
    <link><$MTEntryPermalink encode_xml="1"$></link>
    <description><$MTEntryExcerpt encode_xml="1"$></description>
    <dc:subject><$MTEntryCategory encode_xml="1"$></dc:subject>
    <dc:creator><$MTEntryAuthor encode_xml="1"$></dc:creator>
    <dc:date><$MTEntryDate format="%Y-%m-%dT%H:%M:%S" 
       language="en"$><$MTBlogTimezone$></dc:date>
    <content:encoded><$MTEntryBody encode_xml="1"$><$MTEntryMore 
       encode_xml="1"$></content:encoded>

    <MTEntryIfAllowComments>
      <annotate:reference rdf:resource="<$MTEntryPermalink encode_xml="1"$>" />
      <MTComments>
        <dc:contributor>
          <foaf:person foaf:name="<MTCommentAuthor encode_xml="1">">
             <foaf:homepage rdf:resource="<MTCommentURL encode_xml="1">" />
             <foaf:email rdf:resource="<$MTCommentEmail encode_xml="1"$>" />
          </foaf:person>
        </dc:contributor>
      </MTComments>
    </MTEntryIfAllowComments>

    <MTPingsSent>
      <trackback:about rdf:resource="<$MTPingsSentURL encode_xml="1"$>"/>
    </MTPingsSent>

    <MTEntryIfAllowPings>
      <trackback:ping rdf:resource="<MTEntryTrackbackLink encode_xml="1">"/>
      <MTPings>
        <dcterms:isReferencedBy rdf:resource="<$MTPingURL encode_xml="1"$>" />
      </MTPings>
      </MTEntryIfAllowPings>
    </item>
  </MTEntries>
</rdf:RDF>
Posted by sunouchi at June 18, 2003 11:16 AM