Lab 16 - Extending your iDiary

You've built the iDiary database, and used XSLT to style it in a browser. Now it's time to extend your iDiary by adding RSS feed functionality.

You've seen the RSS logo on many of the sites you visit. Any site that regularly creates new content, like a blog, can use RSS (RDF Site Summary, or Really Simple Syndication) to allow readers to "pull" their content to them by requesting new content from the server on a regular schedule. Applications like Pulp for Mac OS use RSS, as do more traditional products like Sage (a Firefox plugin), and Vienna for MacOS. Apple's iTunes also uses a version of RSS to get podcast information. iTunes uses a more complicated version of RSS 2.0, but for simple blog posts like the iDiary entries, plain old RSS is the way to go.

 

To consider:

My iDiary, RSS style

In this sixteenth lab, you'll use XSLT to create a feed.xml file for your iDiary. As you explore, review your answers from the To consider: section above. Have you changed your mind about any of them?

Learning more

Imagine you are ready to add RSS functionality to your iDiary page. By adding an RSS feed, people could get your updated entries automatically sent to them. Most blog platforms like Blogger and WordPress give you the option of creating an RSS feed that updates "automatically". They have RSS feeds themselves; here's what WordPress' feed looks like in your web browser: http://wordpress.org/news/feed/

The iDiary page is a lot simpler, and doesn't have a database underneath it to make generating RSS feeds easy. What tools might you have at your disposal?

  1. Before we get too far, let's look at the correct syntax for RSS 2.0, and see if we recognize anything from our iDiary.xml. For what we need, we're going to use the minimum required elements of the RSS 2.0 specification. If you'd like to know the full details, you can read more about the specification at Harvard Law School's Berkman Center's hosting of the RSS 2.0 Specification.

    Here's an example of the minimum syntax: <?xml version="1.0" encoding="UTF-8" ?> <rss version="2.0"> <channel> <title>My iDiary</title> <link>http://www.myidiary.com/myname/</link> <description>Stuff I Like!</description> <item> <title>First Entry</title> <link>http://www.myidiary.com/myname/first.html</link> <description>My First iDiary Entry</description> </item> <item> <title>Second Entry</title> <link>http://www.myidiary.com/myname/first.html</link> <description>My Second iDiary Entry</description> </item> </channel> </rss>

    You can see that the structure and syntax for the required elements is pretty simple. Take a close look. What is the root element? Do you see elements that would be pretty close matches to the elements in your iDiary.xml file? Make a list of each element in the sample RSS file and its matching iDiary element.

  2. We could create a new RSS file by hand. Using the iDiary.xml file, we could copy and paste contents of those elements into the skeleton of an RSS file. This is not too much work for the small number of entries we currently have, but what if you had 20 entries? 40? 100? The copy and paste method sounds less and less appealing. But we've already used a tool that transforms one kind of file into another kind of a file, and that's XSLT. You may be thinking, but XSLT is like a stylesheet, and controls the visual presentation and organization of XML files - how am I going to use it with creating an RSS file? But XSLT can be used to transform an XML file into another XML file, rearranging or hiding elements as necessary, very much like using one of the database operations from Lab 15.

    Now that we know we can use our XSLT skills, our next step is to make a skeleton XSLT file that has the elements we want the iDiary elements to transform into: <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match=""> <rss version="2.0"> <channel> <title></title> <link></link> <description></description> <item> <title></title> <link></link> <description></description> </item> </channel> </rss> </xsl:template> </xsl:stylesheet>

    It looks like we'll need to map these iDiary elements to their related RSS elements:

    • The <title> element inside the iDiary <entry> element will be the <title> element inside the RSS <item> element.
    • The <cool> element inside the iDiary <entry> element will be the <description> element inside the RSS <item> element.
    • The first <link> element inside the iDiary <cool> element will be the <link> element inside the RSS <item> element. This is fudging a bit, because the RSS <link> element is really meant to contain the URL to the article or post. But since our iDiary entries are not separate pages, and they also do not have URLs assigned to them, we'll use the outbound links in each entry to practice out XSLT skills.

  3. In our past XSLT experience, we used template matching to match from outer to inner nested elements. But there's a bit of a challenge to this transformation that means we'll need to find a better tool. Have you spotted it? Here's the issue - iDiary's nesting looks like this:

    <entry> <date></date> <cool> <title></title> </cool> </entry>

    But RSS' nesting looks like this:

    <item> <title></title> <link></link> <description></description> </item>

    Our challenge here is where the <title> element is nested in iDiary. We need to be able to pull it out of the <cool> element so that it is a sibling element to the description, not a child element. We can't do that with the template matching we have used before. XSLT has two great elements that, when we use them together, we can get exactly what we want where we want it. Those elements are <xsl:for-each select=""></xsl:for-each>, and <xsl:value-of select=""/>. As you'll see, these elements work very much like JavaScipt functions in that they return values to the calling "script".

    The for-each element allows us to select an element like <entry> and loop through every instance of it in our XML file. The value-of element allows us to get the value of the element, or the content inside the tag (or the tag's attribute). Before we continue, take a moment to read more about <xsl:for-each> and <xsl:value-of> at the W3School's XSLT Tutorial site.

  4. Let's begin to fill out our skeleton. Taking a closer look, it looks like we'll need to copy and paste the <channel> element's child elements, but we only have to do that one time. Not so bad! We also need to select the group of <entry> elements in iDiary, and act on them. Here are the relevant changes:

    <channel> <title>My iDiary</title> <link>iDiary.xml</link> <description>This is a record of the most interesting thing I found out each day that's worth remembering. </description> <xsl:for-each select="entry"> <item> <title></title> <link></link> <description></description> </item> </xsl:for-each> </channel>
  5. Finally, we'll put the <xsl:value-of select=""/> elements inside the RSS elements. We'll make each of the following changes one at a time, and check our results by making a copy of the iDiary.xml file and pointing it to this new stylesheet. Why make a copy? If our iDiary.xml page is currently displaying content over the Web, changing the .xsl file it points to will make the web-based display pretty darned ugly, since we aren't including any html tags in this transform. So:

    • If you haven't yet, save your current XSLT file with a useful name and the .xsl extension in the same directory as your iDiary.xml file.
    • Make a copy of your iDiary.xml file in the same directory as your iDiary.xml file, and save it as a different filename.
    • Open the iDiary copy, and edit the value for the href in this statement to point to the RSS XSL file: <?xml-stylesheet type="text/xsl" href=""?>
    • Open the iDiary copy in your browser. Looks horrible, doesn't it? good thing we made a copy! Remember, our transform has no html tags associated with it. What you are looking for at this stage is that the element contents are in the right order and are the right content.
    • Now, for the magic: right-click on the browser window and choose Web Developer > View Source > View Generated Source. It won't be formatted very well, but that's the source code your new RSS XSLT is generating! You won't see much in this iteration, but you'll use this tool every time you make a change to check your work. it isn't the most elegant debugging too, but it does work.

    As we fill in our skeleton, some things to pay attention to in the syntax include getting the value of the title from inside the <cool> element, and putting it in the properly nested RSS <title> element with <xsl:value-of select="cool/title"/>. Also remember that we made the decision to use the outbound links in iDiary's <link> element to populate the RSS <link> element. This presents a problem for entries where more than one <link> element is present. Because only one <link> child element can be present in the RSS <item> element, we use another for-each loop that looks at all of the <link> elements that are children of the <cool> element, and only gets the first one of those: <xsl:for-each select="cool/link[1]">. Once we have the first <link> element, we can get the value of the url attribute by using <xsl:value-of select="@url"/>, and putting it inside the RSS <link> tags. Here's the finished stylesheet:

    <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="idiary"> <rss version="2.0"> <channel> <title>My iDiary</title> <link>iDiary.xml</link> <description>This is a record of the most interesting thing I found out each day that's worth remembering. </description> <xsl:for-each select="entry"> <item> <title><xsl:value-of select="cool/title"/></title> <xsl:for-each select="cool/link[1]"> <link><xsl:value-of select="@url"/></link> </xsl:for-each> <description><xsl:value-of select="cool"/></description> </item> </xsl:for-each> </channel> </rss> </xsl:template> </xsl:stylesheet>
  6. What's left to do? Open the iDiary copy one last time, and right-click on the browser window. Choose Web Developer > View Source > View Generated Source, select all the text in the DOM Source of Selection window, and copy and paste it into a new file called feed.xml. You may want to go through and tidy it up a bit, adjusting the white space so it's easier for you to read. You're ready to upload the file to a directory on your webserver, to register it by XXXXXX, and to add an RSS icon to your iDiary page.

    But what happens when you add a new iDiary entry? With the tools you have available to you, what will you have to do to keep the RSS feed updated? List the steps. Do you think it will be worth it?

Moving on

Unlike the other labs in this series, this lab was designed to walk you through the steps of solving a technology problem without the solution you completed necessarily being the "best" one. There are definitely times when you can tell in advance that the effort you want to put into solving a problem on your own is clearly outweighed by the ease of using a pre-built solution. Sometimes though, you'll need to go through at least some of the steps towards solving a problem to see if what you think might be a good solution really is a good solution.

How can we evaluate this approach? In this case, we need to consider the variety of iDiary creators. Someone who updates their iDiary page infrequently may not mind going through all the steps to update the RSS feed file. Similarly, someone with more programming experience may know a way to automate some or all of the steps to update the RSS feed file, will write that code one time, and be done. But frequent updaters who do not have those programming skills are likely to get frustrated at the additional work required to keep their RSS feeds current. Most of us probably fall into this last group.

So why did we go through all these steps? What did we get out of going through these steps, even if we decide this method of adding RSS feeds to our sites isn't right for us?

Seems like a pretty significant list of things we've learned, considering it's from an approach we've decided not to take.