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 DataGrid
s to display data from the two tables. The AllowSorting
property of the DataGrid
s is set to True
. This allows the user to click on column headings in the DataGrid
s 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)
GetNewsFeedItemsFromSite(strUrl, intSiteID)
Private Sub GetNewsFeeds()
Me.OleDbdaSites.Update(Me.DataSet11.rsssites)
Dim i As Integer, j As Integer
i = Me.DataSet11.rsssites.Rows.Count
If i >= 1 Then
For j = 0 To i - 1
Dim dr As DataRow
Dim strUrl As String, intSiteID As Integer
dr = Me.DataSet11.rsssites.Rows(j)
If dr.Item("View") = True Then
strUrl = dr.Item("XMLURL").ToString
intSiteID = Val(dr.Item("id").ToString)
GetNewsFeedItemsFromSite(strUrl, intSiteID)
End If
Next
End If
Me.OleDbdaItem.Fill(Me.DataSet11.item)
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
intCount = ds.Tables("Item").Rows.Count
If intCount > 0 Then
For intRow = 0 To intCount - 1
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
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()
Next
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
dr = Me.DataSet11.ViewItems.Rows(i - 1)
strUrl = dr.Item("link").ToString
webBrowser0.Navigate(strUrl)
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 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
MsgResult = MessageBox.Show("Items NOT selected will be " & _
"deleted from the database. Do you want to proceed?", _
"Data Base Deletion", MessageBoxButtons.YesNoCancel, _
MessageBoxIcon.Warning)
If MsgResult = DialogResult.Yes Then
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()
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
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.