Search

Creating an Online RSS News Aggregator with ASP.NET Part 4

0 views

Displaying the News Items for a Particular Syndication Feed The next task that faces us is creating the DisplayNewsItems.aspx Web page. This page should display the titles of the news items in the selected syndication feed as hyperlinks such that when the hyperlink is clicked the description of the news item is shown in the bottom right frame. This task presents us with two primary challenges:

  • Accessing the RSS syndication feed from the feed's specified URL, and
  • Transforming the XML received into the appropriate HTML.
  • Fortunately with the .NET Framework, neither of these two challenges is particularly daunting. For the first task, realize that remote XML data can be loaded into an XmlDocument object with just two lines of code. For the second task, displaying XML in an ASP.NET Web page is a cinch with the ASP.NET XML Web control. The XML Web control is designed to display raw or transformed XML data on a Web page. The first step in using the XML Web control is specifying the XML data source. This can be accomplished in a bevy of ways through three different properties. Using the Document property, you can assign an XmlDocument instance as the XML data source for the XML Web control. If the XML data exists in a file on the Web server's file system, you can use the DocumentSource property, providing either a relative or absolute path to the XML file. Finally, if you have the XML data in a string, you can set this string to the XML Web control's DocumentContent property. Any of these three approaches can be used to associate XML data with the XML Web control. Typically we'll want to transform the XML data in some manner before displaying it on the Web page. The XML Web control allows us to specify an XSLT stylesheet that will apply the transformation. Similar to the XML data, the XSLT stylesheet can be specified in one of two ways through one of two properties: the Transform property can be assigned an XslTransform instance or the TransformSource property can be set to a relative or absolute file path to the XSLT stylesheet on the local Web server. In a moment, we'll see an example of the XML Web control in action. Let's get to creating the DisplayNewsItems.aspx Web page. Before we add an XML Web control and start creating the code-behind class, we need to add a small bit of client-side JavaScript to the HTML portion. Specifically, add the following <script> block in the <head> tag of the HTML portion: <script language="javascript"> &nbsp // display a blank page in the bottom frame when the news items loads &nbsp parent.rbottom.location.href = "about:blank"; </script> This client-side JavaScript displays a blank page in the bottom right frame whenever DisplayNewsItems.aspx is loaded. To understand why we want to do this consider the following situation that can unfold if we omit this <script>block: 1. The user clicks on a syndication feed from the left frame, thereby loading the feed's news items in the top right frame. 2. The user then clicks one of the news items from the top right frame, thereby loading the news item's details in the bottom right frame. 3. Now the user clicks on a different syndication feed from the left frame, thereby loading the new feed's news items in the top right frame. At this point, the details from the previous syndication feed's news item are still in the bottom right frame! The above client-side script code alleviates this glitch by "whipping out" the contents of the bottom right frame every time a syndication feed from the left frame is clicked. Now that we have taken care of that client-side scripting issue, let's turn our attention to adding the needed XML Web controls. Once you have added the XML Web control, set its ID property to xsltNewsItems and its TransformSource property to NewsItems.xslt (the name of the XSLT stylesheet we'll create next). Now, in the Page_Load event handler we need to retrieve the remote RSS syndication file in an XmlDocument instance, and then set the XML Web control's Document property to this XmlDocument instance. private void Page_Load(object sender, System.EventArgs e) { &nbsp &nbsp // See if the news items for this feed are in the Data Cache &nbsp&nbsp int feedID = Int32.Parse(Request.QueryString["FeedID"]); &nbsp&nbsp // Connect to the Database to find out the URL to the RSS &nbsp&nbsp SqlConnection myConnection = new SqlConnection(connection string); &nbsp&nbsp // Retrieve the SQL URL for the Remote RSS syndication file &nbsp&nbsp string SQL_QUERY = "SELECT URL, UpdateInterval FROM Feeds " + &nbsp&nbsp&nbsp&nbsp "WHERE FeedID = @FeedID"; &nbsp&nbsp SqlCommand myCommand = new SqlCommand(SQL_QUERY, myConnection); &nbsp&nbsp SqlParameter feedParam = new SqlParameter("@FeedID", &nbsp&nbsp&nbsp&nbsp SqlDbType.Int, 4); &nbsp&nbsp feedParam.Value = feedID; &nbsp&nbsp myCommand.Parameters.Add(feedParam); &nbsp&nbsp myConnection.Open(); &nbsp&nbsp string feedURL = myCommand.ExecuteScalar().ToString() &nbsp&nbsp myConnection.Close(); &nbsp&nbsp // Now that we have the feed URL, load it in into an XML document &nbsp&nbsp XmlDocument feedXML = new XmlDocument(); &nbsp&nbsp feedXML.Load(feedURL); &nbsp&nbsp xmlNewsItems.Document = feedXML; } The most germane lines of code in the Page_Load event handler are the last three. These three lines of code create the new XmlDocument object, load in the remote RSS feed, and assign the XmlDocument object to the XML Web control's Document property. Isn't it impressive how simple it is to access remote XML data and display it in an ASP.NET Web page? All that we have left to do now is create the XSLT stylesheet, NewsItems.aspx. This first draft of this stylesheet can be seen below: <?xml version="1.0" encoding="UTF-8" ?> <xsl:stylesheet version="1.0" &nbsp &nbsp&nbsp&nbsp xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> &nbsp <xsl:output method="html" omit-xml-declaration="yes" /> &nbsp <xsl:template match="/rss/channel"> &nbsp&nbsp <b><xsl:value-of select="title" &nbsp&nbsp&nbsp&nbsp disable-output-escaping="yes" /></b> &nbsp&nbsp <xsl:for-each select="item"> &nbsp&nbsp&nbsp <li> &nbsp&nbsp&nbsp&nbsp <a> &nbsp&nbsp&nbsp&nbsp&nbsp <xsl:attribute name="href"> &nbsp&nbsp&nbsp&nbsp&nbsp&nbsp DisplayItem.aspx?ID=<xsl:number value="position()" /> </xsl:attribute> &nbsp&nbsp&nbsp <xsl:attribute name="target">rbottom</xsl:attribute> &nbsp&nbsp&nbsp&nbsp <xsl:value-of select="title" &nbsp&nbsp&nbsp&nbsp&nbsp disable-output-escaping="yes" /> &nbsp&nbsp&nbsp &nbsp </a> &nbsp&nbsp&nbsp (<xsl:value-of select="pubDate" />) &nbsp&nbsp&nbsp </li> &nbsp&nbsp </xsl:for-each> &nbsp </xsl:template> </xsl:stylesheet> This XSLT stylesheet has a single template that matches on the /rss/channel XPath expression, outputting the value of the <title> element in a bold font. Next, it iterates through each of the <item> elements and, for each, displays a hyperlink to DisplayItem.aspx, passing the element's position through the querystring. Note that this hyperlink also has its target attribute set to rbottom, the name of the bottom right frame. Finally, it displays the value of the <pubDate> element after each news item title. There are a couple of items in the XSLT stylesheet that not everyone may be familiar with. The first of these is the disable-output-escaping="yes" attribute in the elements. Essentially, this attribute setting informs the XSLT engine that it should not escape those illegal XML characters-&, , " and '. To understand what this accomplishes, realize that if this attribute were not set (or was set to the default value, "no"), then if the title contained an escaped & as &, the resulting HTML would have & in it as well, as opposed to just &. If you think about this for a bit, you can see that this can cause a multitude of problems. For example, if the title for a syndication file is: "Matt's <i>Cool</i> Blog", then if output escaping is not disabled, then the output would remain "Matt's <i>Cool</i> Blog" and would be shown in the Web page as, "Matt's <i>Cool</i> Blog". With disable-output-escaping="yes", however, the output is not escaped and is read as "Matt's <i>Cool</i> Blog", thereby displaying in the Web page as the desired "Matt's Cool Blog". Another thing to note is the <a> element. Realize that this funky syntax ends up generating the following output: <a href="DisplayItem.aspx?ID=position">news item title</a> The reason we have to use this syntax is because in order to add an attribute to an element in an XSLT stylesheet you need to create the element and then inside of the element's tags, use the <xsl:attribute> syntax. There are some examples of this syntax available online at W3Schools, The <xsl:attribute> Element page. Finally, note that the ID querystring value in the hyperlink is assigned the value from the <xsl:number> element, with a value of the position() function. The element simply emits a number. The position() function is an XPath function that returns the ordinal position of the current node in the XML document. This means the first news item will have a position() value of 1; the second, a position() value of 2; and so on. We need to record this value and pass it along via the querystring so that when the DisplayItem.aspx Web page is called, it knows what item from the RSS syndication feed we are interested in viewing. The astute reader may have realized that our XSLT stylesheet is not complete due to the fact that the FeedID parameter is not passed through the querystring to the DisplayItem.aspx Web page. To see why this is a problem, recall that we are sending in the ID querystring parameter the ordinal position of the element the user is interested in viewing the details for. That is, if the user clicks on the fourth news item, the page DisplayItem.aspx?ID=4 will be loaded in the bottom right frame. The problem is that DisplayItem.aspx cannot determine what feed the user is interested in viewing. There are a couple of ways to figure this out, such as having the bottom right frame use client-side JavaScript to read the URL of the top right frame, thereby ascertaining the value of FeedID. A simpler way, in my opinion, is to merely pass along the FeedID value through the querystring along with the ID parameter. One difficulty that arises from this is that FeedID is not present in the RSS XML data, which is what the XSLT stylesheet is working with. The DisplayNewsItems.aspx Web page knows the FeedID, though, and needs to somehow let the XSLT stylesheet know this value. This can be accomplished through the use of XSLT parameters. Using XSLT parameters is fairly straightforward. In the XSLT stylesheet, you need to add inside the <xsl:template> element an <xsl:param> element, which provides the name for the parameter. Let's call this parameter FeedID: <xsl:stylesheet version="1.0" &nbsp&nbsp xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/rss/channel"> <xsl:param name="FeedID" /> ... </xsl:template> </xsl:stylesheet> Now, the parameter can be used in an <xsl:value-of> element using the following syntax: <xsl:value-of select="$parameterName" /> Therefore, we can add the FeedID querystring parameter to the hyperlink by adding the following to our existing XSLT stylesheet: <a> &nbsp <xsl:attribute name="href">DisplayItem.aspx?ID=<xsl:number &nbsp&nbsp value="position()" /> &FeedID=<xsl:value-of select="$FeedID" &nbsp&nbsp&nbsp /></xsl:attribute> Note that we have an ampersand (escaped to &) after the ID querystring parameter, and then have the querystring parameter FeedID with the value from the FeedID parameter. That's all we have to add to our XSLT stylesheet. What remains is to set the parameter's value programmatically in the Page_Load event handler of the DisplayNewsItems.aspx Web page. This is accomplished using the XsltArgumentList class. This class contains an AddParameter() method. Once we have created an instance of this class and added the parameter, we simply set the class instance to the XML Web control's TransformArgumentList parameter. The following code shows the updated Page_Load event handler for DisplayNewsItems.aspx: private void Page_Load(object sender, System.EventArgs e) { ... &nbsp // Now that we have the feed URL, load it in into an XML document &nbsp XmlDocument feedXML = new XmlDocument(); &nbsp feedXML.Load(feedURL); &nbsp xmlNewsItems.Document = feedXML; &nbsp // Add the FeedID parameter to the XSLT stylesheet &nbsp XsltArgumentList xsltArgList = new XsltArgumentList(); &nbsp xsltArgList.AddParam("FeedID", "", feedID); &nbsp xmlNewsItems.TransformArgumentList = xsltArgList;} *This article originally appeared on the ASP.NET Dev Center at MSDN Scott Mitchell, author of five ASP/ASP.NET books and founder of 4GuysFromRolla.com, has been working with Microsoft Web technologies for the past five years. An active member in the ASP and ASP.NET community, Scott is passionate about ASP and ASP.NET and enjoys helping others learn more about these exciting technologies. For more on the DataGrid, DataList, and Repeater controls, check out Scott's book ASP.NET Data Web Controls Kick Start (ISBN: 0672325012). Read his blog at : http://scottonwriting.net

    Suggest a Correction

    Found an error or have a suggestion? Let us know and we'll review it.

    Share this article

    Comments (0)

    Please sign in to leave a comment.

    No comments yet. Be the first to comment!