Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

RSS News Reader

0.00/5 (No votes)
10 May 2005 1  
A VB.NET RSS news reader. RSS sites are stored in an Access database, and items can be selected from a DataGrid. Selected news items are displayed in an embedded browser.

Sample Image

Introduction

This is a simple RSS News Reader. A list of RSS feed sites is contained in an Access database. The news sites are displayed in a DataGrid, and the user can select news sites of interest. Following this step, the user can get all the news items in the selected RSS news feed sites. These items are displayed in another DataGrid. The user selects news items of interest based on item titles and/or descriptions. The selected news items are displayed in a browser, with a forward and backward scan through the selected news items.

Background

It helps if the user has an understanding of Access databases and the VB.NET interface

Using the code

This program can be customized to add a search function that will enable users to select news items based on titles, descriptions, or categories. The ReadXML method of a DataSet is used to read XML data from a site. This works for RSS 2.0 compliant sites. The database is Access and can be upgraded. Note that in the source code, the database file, rss.mdb is included in the source code folder. When you compile it, make sure you first put it in the bin folder and then compile the code. The code is written to look for the database file in the bin folder. It will display an error if it is not found in the bin folder.

Help is configured from my website and I have set up the site to assist with user queries. I plan to add material to this site over time. The code illustrates simple VB.NET coding and I use it to show database connectivity, SQL queries, DataGrid customization, menus, application data, and XML data management.

The program uses OLEDB data adapters to connect to an Access database. The Access database file rss.mdb contains two tables, rssSites and Items. The rssSites table holds a list of RSS news sites and site descriptions. The XMLURL field in this table has the site address. The SiteName and Description fields have the name of the news site and a description of the type of news available at the site. I have added 72 sites and the user can add any other sites of interest and edit this data. At present, you need MS Access to open and edit this file. I plan to add an edit page to the RSS News Reader to allow the user to manage this table from the program�s GUI. The Items table is designed to hold the news item information from the news sites selected by the user. This table can grow over time, and I have written code to help the user in maintaining this table. Users need to note that news feeds do not remain online forever, and old news item URLs will not connect after a few days. I have not added a date field for this table. The RSS data contains author and date published information. The user can easily modify the program to add these features. Each table has a Boolean field named View that is set to True when the user selects the news site or news item. There is a query ViewItems that filters the records from the Items table that have View set to True; these are the items selected by the user. There is a one to many relationship between the rssSites and Items tables.

I use OLEDB connection wizards to simplify the task of connecting to the database. Of course, you can write more efficient code to connect to the database, if you have experience doing this. There are three OLEDB data adapters, OleDbdaSites to get the rssSites table, OldDbdaItems to get the Items table, and OleDbdaViewItems that gets the ViewItems query from the database.

Table Styles for a DataGrid

Let�s start with our first step, the GUI. There are two DataGrids to display data from the two tables. The AllowSorting property of the DataGrids is set to True. This allows the user to click on column headings in the DataGrids and sort the data alphabetically. Finally, the TableStyles property is set to customize the DataGrid columns. I used the property window in the designer to customize the columns. Open the Collection Editor for Table Styles, and proceed to the Grid Column Styles collection. Add one boolean column and two text box columns. The mapping name property of the column style property is set to the field value. Set the Boolean column to display the View column (boolean item) and use the two text columns to display the site name and site descriptions. Set the AllowNull property of the boolean column to False. The default is a three value check box with True, Null and False. Setting this property to False makes the check box go to only True or False. The ReadOnly property determines if the user can edit the values for the column. This is set to False for the View column (since users must be allowed to select the sites they want to visit, or items they want to see) and False for the other columns to prevent users from editing these values.

A menu is added to simplify navigation through the GUI. The code for menu item mnuGetFeeds, calls the procedure GetNewsFeeds which gets a list of news items from sites selected (View = True) in the DataGrid, dgdSites. The code runs only when there are items in the rssSites table in the cached DataSet. A DataRow object is created to hold each row and the code loops through the rows in the DataSet with View set to True.

Dim dr As DataRow

The URL of the news site (value in the XMLURL field of the rssSites table) and the ID number are passed to the procedure, GetNewsFeedItemsFromSite.

strUrl = dr.Item("XMLURL").ToString
intSiteID = Val(dr.Item("id").ToString)
' call procedure to read URL and get RSS Item feed

GetNewsFeedItemsFromSite(strUrl, intSiteID)
Private Sub GetNewsFeeds()
    ' Update database to make sure sites selected are stored in database

    Me.OleDbdaSites.Update(Me.DataSet11.rsssites)
    Dim i As Integer, j As Integer
    i = Me.DataSet11.rsssites.Rows.Count
    If i >= 1 Then
        ' Loop from first (index 0) to i-1th (last) item in the rss sites table

        For j = 0 To i - 1
            Dim dr As DataRow
            Dim strUrl As String, intSiteID As Integer
            dr = Me.DataSet11.rsssites.Rows(j)
            ' select only sites with view checkbox selected by user.

            If dr.Item("View") = True Then
                strUrl = dr.Item("XMLURL").ToString
                intSiteID = Val(dr.Item("id").ToString)
                ' call procedure to read URL and get RSS Item feed

                GetNewsFeedItemsFromSite(strUrl, intSiteID)
            End If
        Next
    End If
    ' Refresh the item dataset with the updated data from the item table

    Me.OleDbdaItem.Fill(Me.DataSet11.item)
    ' Display the items dataset in the datagrid

    Me.dgdItems.Refresh()
End Sub

The procedure GetNewsFeedItemsFormSite creates a new DataSet and uses the ReadXML method of the DataSet to read and parse the XML data from the site.

Dim ds As New DataSet
On Error GoTo errsub
ds.ReadXml(strUrl)

If the site�s XML cannot be parsed due to an error, the OnError statement traps the error and displays an error message. The RSS feed is XML data that is read into tables in the DataSet. The table names are rss, channel, image, item, and guid. The rss table has a column named version; value of 2.0 for RSS 2.0. The channel table has columns named title, link, description, copyright, language and lastBuildDate. This is the channel's description. Note that en-us is US English for language. The image table has columns named url, title, link. The item table has columns named title, link, description, author, pubDate for each item in the channel. The guid table has columns named isPermaLink and guid_Text.

strUrl = ds.Tables("Item").Rows(intRow).Item("link").ToString

The URL of the news item (each news item in an RSS feed has its own unique URL) is read from the XML data passed into the data set table Item.

Access has a problem with SQL statements containing apostrophes and the Replace statement replaces each apostrophe with a double apostrophe to avoid errors. If you use procedures in MS SQL Server, you can use parameters to pass the data, and avoid this code. In addition, Access limits text fields to 255 characters and I have code to limit string length.

strItemURL = SQLString(strItemURL, 250)

The function SQLString that does this task is shown later in the notes.

A new command is created to insert the data into the Items table. If you choose to also store Author and pubDate information, you need to add the columns to your Access database, read in and clean up the data, and then modify the Insert command. Note the use of the underscore to wrap long strings in your code and make them readable. There must be a blank space before the underscore.

MyCommand.CommandText = _
    "Insert into Item (title,link,description,siteid) VALUES " & _
    "('" & strTitle & "','" & strUrl & "','" & _
    strDescription & "'," & intSiteID & ")"

The connection created earlier by the data adapter wizard is used here.

If Me.OleDbConnection1.State <> ConnectionState.Open Then
  Me.OleDbConnection1.Open()
End If                          
MyCommand.Connection = Me.OleDbConnection1

Make sure the connection is open, and open it if is already closed. The command is repeated in the next cycle of the For-Next loop, and the command must be deleted before it is recreated.

MyCommand.Dispose()
Private Sub GetNewsFeedItemsFromSite(ByVal _
                 strURL As String, ByVal intSiteID As Integer)
    Dim intRowsAffected As Integer
    On Error GoTo errsub
    Dim ds As New DataSet
    ds.ReadXml(strURL)
    Dim intCount As Integer, intRow As Integer
    Dim strTitle As String, strDescription As String
    Dim strItemURL As String
    ' get number of rows in item table from XML page dataset

    intCount = ds.Tables("Item").Rows.Count
    ' you have data to add to the item table

    ' in the database only if there is at least one row

    If intCount > 0 Then
        ' loop through rows in the item table in the XML page dataset

        For intRow = 0 To intCount - 1
            'Get values from dataset

            ' Replace apostrophe with double

            ' apostrophe for Access text fields

            ' Limit string length for Access database

            ' text field. This can be longer if

            ' you use Oracle, DB2, or SQL Server

            strItemURL = ds.Tables("Item").Rows(intRow).Item("link").ToString
            strItemURL = SQLString(strItemURL, 250)

            strTitle = ds.Tables("Item").Rows(intRow).Item("title").ToString
            strTitle = SQLString(strTitle, 100)

            strDescription = _
              ds.Tables("Item").Rows(intRow).Item("description").ToString
            strDescription = SQLString(strDescription, 250)

            Dim MyCommand As New OleDb.OleDbCommand
            ' Insert news feed items from selected RSS sites into items table

            ' Other fields like author

            ' and data of publication can also be added here

            MyCommand.CommandText = _
                "Insert into Item (title,link,description,siteid) VALUES " & _
                "('" & strTitle & "','" & strItemURL & _
                "','" & strDescription & "'," & intSiteID & ")"
            If Me.OleDbConnection1.State <> ConnectionState.Open Then
                Me.OleDbConnection1.Open()
            End If
            MyCommand.Connection = Me.OleDbConnection1
            intRowsAffected = MyCommand.ExecuteNonQuery()
            MyCommand.Dispose()
            '  MsgBox("insert done" & intRowsAffected.ToString & _

            '              " rows", MsgBoxStyle.Information, "Message")

        Next
        '   MsgBox("done with items", MsgBoxStyle.Information, "Message")

    Else
        MsgBox("No sites selected; No news items", _
                        MsgBoxStyle.Information, "Message")
    End If
    Exit Sub
errsub:
    MsgBox(Err.Description, MsgBoxStyle.Critical, "Error")
End Sub

The Replace command is used to replace a single apostrophe in a field�s value with a double apostrophe. If a single apostrophe is passed to SQL, it will be seen by Access as the end of the SQL statement.

strSQL = Replace(strSQL, "'", "''")

Note this is an apostrophe enclosed in double quotes before the comma, and two apostrophes enclosed in double quotes after the comma.

Private Function SQLString(ByVal strSQL As String, _
                ByVal intLength As Integer) As String
    strSQL = Replace(strSQL, "'", "''")
    If strSQL.Length > intLength Then
        strSQL = strSQL.Substring(0, intLength)
    End If
    Return strSQL
End Function

After filling the Items table with the news items from the selected sites, the user selects the items he/she wants to view. The way I have set it up, the system remembers all news items that were previously added to the database, and the list needs to be culled, to prevent it from growing too large. I have code under the News Items menu to delete items not selected, or to delete all items. Since old news feed URLs are not maintained by news sites, retaining very old links is not profitable. You can alter the code to automatically delete old items based on date of publication.

The menu item Get Selected News Items under News Items, has code to go to the news site and pull up the item and display it in a browser window. I have used the AxWebBrowser control that comes with VS.NET. Add the browser control to the project from Project, Add Reference, COM items, and select and add the Microsoft Internet Controls. I use the FireFox browser myself and I plan to use that in a future version.

Me.OleDbdaViewItems.Fill(Me.DataSet11.ViewItems)
intItemstoView = Me.DataSet11.ViewItems.Rows.Count

The ViewItems table in the DataSet contains the output from the ViewiITems query in the database. This selects the news items selected by the viewer. The number of items selected by the viewer is stored in a form level variable intItemstoView.

The GetFeed procedure navigates the browser to the selected site�s URL. Note, the parameter refers to the index number of the item.

GetFeed(intItemViewed)

Again, a DataRow object is used to get the values in each selected row, and the value in the link (hyperlink) column is stored in a string variable strURL. This is the URL of a single news item, not for the entire site. The web browser object is set to navigate to the site. The site�s URL is displayed in an output label and progress bar is used to show the number of selected sites that have been viewed.

Private Sub GetFeed(ByVal i As Integer)
    On Error GoTo Errsub
    Dim strUrl As String
    Dim dr As DataRow
    'Select the row (base 0) from the viewitems dataset

    dr = Me.DataSet11.ViewItems.Rows(i - 1)
    strUrl = dr.Item("link").ToString
    'Navigate to the site and display in browser

    webBrowser0.Navigate(strUrl)
    'Item being displayed in browser

    Me.lblPosition.Text = intItemViewed.ToString & " of "_
       & intItemstoView.ToString & " items. " & _
       webBrowser0.LocationURL.ToString
    Exit Sub
ErrSub:
    MsgBox(Err.Description & " in GetFeed Procedure. ", _
                        MsgBoxStyle.Information, "Error")
End Sub

Users can navigate from one selected news item to the next using the Next/Previous buttons, menu items under the Browser menu panel, or function keys. Function keys F11 and F12 are mapped to the menu items in the Browser menu panel using the shortcut property in the menu items property page.

Private Sub procNextPage()
    ' If the page being viewed is not the last page, view next page

    If intItemViewed < intItemstoView Then
        intItemViewed = intItemViewed + 1
        GetFeed(intItemViewed)
        pgsBrowser.Value = intItemViewed
    Else
        MsgBox("Last Item Displayed", MsgBoxStyle.Information, "Error")
    End If
End Sub

The form level variable intItemViewed is incremented and the corresponding item displayed in the browser using the GetFeed method. Similar code is used to navigate to the previous page.

The user can delete items in the item table by making the appropriate choice in the News Items menu item. Note the use of additional verification before deleting items from a database to prevent accidental deletion.

MsgResult = MessageBox.Show("Items NOT selected will be deleted" & _ 
   " from the database. Do you want to proceed?", "Data Base Deletion", _
   MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning)

The MessageBox.Show method returns a value of type DialogResult which can be used to determine the user�s response to a MessageBox. The box used here is a Yes/No/Cancel type message box and it contains a Warning icon to inform the user of the importance of the selection.

If MsgResult = DialogResult.Yes

The code proceeds to delete the data only if the user clicks on the Yes choice.

MyCommand.CommandText = "Delete from Item where view = False"

The command is set to a SQL statement that will delete all items that have not been selected for viewing. The parent connection from the data adapter wizard is opened if it is not open and used. The command is cleared after it is used, and the DataSet is refreshed to show the new, updated data. The DataGrid is also refreshed with the new data.

Me.DataSet11.item.Clear()
Me.OleDbdaItem.Fill(Me.DataSet11.item)
Me.dgdItems.Refresh()
Private Sub mnuDeleteItemsNotSelected_Click(ByVal sender As _
        System.Object, ByVal e As System.EventArgs) _
        Handles mnuDeleteItemsNotSelected.Click
    Dim MsgResult As DialogResult, intRowsAffected As Integer
    ' Warning message before deleting items from the database

    MsgResult = MessageBox.Show("Items NOT selected will be " & _ 
                "deleted from the database. Do you want to proceed?", _
                "Data Base Deletion", MessageBoxButtons.YesNoCancel, _
                MessageBoxIcon.Warning)
    'Proceed only after user confirmation

    If MsgResult = DialogResult.Yes Then
        ' save view item state in database

        'This saves the current state of the items table, 

        'and records user selections before deleting

        ' items not selected for viewing

        'If this is not done, then the delete command 

        'will remove items selected for viewing as well

        Me.OleDbdaItem.Update(Me.DataSet11.item)
        Dim MyCommand As New OleDb.OleDbCommand
        MyCommand.CommandText = "Delete from Item where view = False"
        If Me.OleDbConnection1.State <> ConnectionState.Open Then
            Me.OleDbConnection1.Open()
        End If
        MyCommand.Connection = Me.OleDbConnection1
        intRowsAffected = MyCommand.ExecuteNonQuery()
        MyCommand.Dispose()
        'Clear dataset and fill it with new, updated item table from database

        Me.DataSet11.item.Clear()
        Me.OleDbdaItem.Fill(Me.DataSet11.item)
        Me.dgdItems.Refresh()
    End If
End Sub

The Help menu item displays the developer�s web site for help information. I prefer this to building a WinHelp or HTML help file for packaging with the program. This collects all help queries in one centralized site and helps me continually update help based on user requests.

Private Sub mnuWebHelp_Click(ByVal sender As System.Object, _
         ByVal e As System.EventArgs) Handles mnuWebHelp.Click
    ' Help on web site 

    webBrowser0.Navigate("http://mang.uno.edu/RssReader")
End Sub

The About menu item displays the program�s version, copyright and other related information. Note that you first have to make sure this information is entered in the assemblyInfo.vb file in your project. The Assembly and copyright objects are created and their values set to those for the program. vbCrLf provides a line feed in the message box string.

Private Sub mnuAbout_Click(ByVal sender As System.Object, _
           ByVal e As System.EventArgs) Handles mnuAbout.Click
  Dim asmbly As System.Reflection.Assembly
  Dim copyright As System.Reflection.AssemblyCopyrightAttribute
  asmbly = System.Reflection.Assembly.GetExecutingAssembly
  copyright = _
   asmbly.GetCustomAttributes(GetType(System.Reflection.AssemblyCopyrightAttribute),_
   False)(0)

  MsgBox("Product: " & Application.ProductName & vbCrLf & _
           "Version: " & Application.ProductVersion.ToString & _
           vbCrLf & "Copyright:  " & copyright.Copyright.ToString, _
           MsgBoxStyle.Information, "About")
End Sub

The AssemblyInfo.vb file is a text file. It needs to have an exact syntax to work right.

<Assembly: AssemblyTitle("Rss Reader")> 
<Assembly: AssemblyDescription("Rss Reader - Vb.Net")>
<Assembly: AssemblyCompany("")> 
<Assembly: AssemblyProduct("")> 
<Assembly: AssemblyCopyright("Sathi Mahesh:  May 2, 2005")>

The properties are set to the values you want.

<Assembly: AssemblyVersion("1.0.*")>

The AssemblyVersion property is set for version, release, and build. The * for build allows VS.NET to automatically set the build value.

References: It was Isaac Newton who said "I have only been able to see so far because I have stood on the shoulders of giants". Paraphrasing Newton for my coding, I can say that I have coded as much as I have, only because I have "cut and pasted" code from the work of others. No list of references is going to be complete, given all the Googling I have done to get my code working. However, I must provide a list of those references that have benefited me the most in my work on this code. While not denying the contributions of many others, these stand out as significant to this work.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here