📜 ⬆️ ⬇️

Himself RSS reader

One day, in the middle of the 5th year, the classmate asked me to help her with her labs
C #, as she only studied it. Having learned the task - “write an RSS reader” - and evaluate
situation - the end of the semester - I decided to help her, because I needed the RSS reader myself.


A bit of theory



RSS is a web content transfer format. The name of the technology is the acronym "Really Simple
Syndication ", that is," a really simple transfer of information. "
RSS is an XML dialect. All RSS files must comply with the XML1.0 specification published on the WWW Consortium (W3C) website .
At the top level, an RSS document is an < rss > element with a required attribute.
version indicating the version
RSS (by the way, I made my application based on RSS 2.0). Child element < rss >
- one < channel > element that includes channel information (metadata)
and its contents.
An example RSS 2.0 file looks like this:
<? xml version = "1.0" ? >
< rss version = "2.0" >

< channel >

< title > Liftoff News </ title >

< link > liftoff.msfc.nasa.gov </ link >

< description > Liftoff to Space Exploration. </ description >

')
< item >

< title > Star City </ title >

< link > liftoff.msfc.nasa.gov/news/2003/news-starcity.asp </ link >

< description >
How do Americans get ready to work
International Space Station? They take a crash course in culture, language
and the protocol at Russia's Star City.
</ description >

< pubDate > Tue, 03 Jun 2003 09:39:21 GMT </ pubDate >

</ item >


< item >

< title > Space Exploration </ title >

< link > liftoff.msfc.nasa.gov </ link >

< description >
Sky watchers in Europe, Asia, and parts of Alaska and Canada
on Saturday, May 31st.
</ description >

< pubDate > Fri, 30 May 2003 11:06:42 GMT </ pubDate >

</ item >

</ channel >
</ rss >



Pretty simple file. What does he give us? First, the channel (Channel,
he's Feed) and various information about it - the title, the link to the official website,
channel description, etc.). Secondly, the list of articles / news / records (item) call
as you wish, as well as the properties of these records: title, link, description, date of publication.
In fact, the properties of both the channel and the recording can be much more. All of them
given in the rss 2.0 specification. Her translation, made by Alexey Beshenov , can be found here . The latest specification is available
find here .
To work with the information provided by rss, we need 3 classes: a class for
channel storage, let's call it RssFeed ;
class for storing a list of entries - RssItems ; storage class
Records - RssItem .

Form creation


Open Microsoft Visual Studio 2005 (<span
lang = “en”> Linux guides open MonoDevelop) and create a new application. Call it
Rssreader The interface is simple:

The first and main control that needs to be placed on the form is TableLayoutPanel ,
stretched to full shape (Dock = Fill). This is a very convenient control, it represents
is a table in which every cell you can place an interface element
(an element can occupy several columns and / or rows of a table at the same time). Dimensions
columns can be fixed or specified as a percentage of the size of the table.
This is very useful when resizing a table.
I think the purpose of the remaining elements is clear: TextBox - entering the channel address; Button - button to update the feed; in listview
- displays a list of entries; in WebBrowser - the content is displayed
records
Now we will begin development of the reader. We will start it from the bottom, namely from the class <span
lang = "en-us"> RssItem , then create a class <span
lang = "en-us"> RssItems ,
last to be written
Rssfeed

RssItem


This class provides us with record information. According to the specification of rss 2.0
"All < item > elements are optional, but at least
< title > or < description > must exist. ”
Add a new class to the project, call it RssItem . As a result, we obtain the following:
using
System;
using System.Collections.Generic;
using System.Text;

namespace RssReader

{
class RssItem
{
}
}

Our class will store minimal information about the record: title (title), link
(link to the full text) and description (a brief overview of the message). Add to
Class 3 public fields to store this information:
class RssItem
{
public String title; // record header
public
String link; // link to
full text
public String description; // record description
}


Now add a constructor that will fill in these properties. At the entrance to the designer
must be transferred to a specific entry from rss. Since rss is just a dialect
XML, then we pass the < item > branch to the constructor as input. Yes. Next, the constructor
loops through each tag inside the received record and, meeting
the desired tag, write information from it to the appropriate class property. Implemented
it may be like this:
///

/// Constructor to fill the record

///
/// <param
name = "ItemTag"> xml tag for reading
public
RssItem ( XmlNode ItemTag)

{

//
view all post tags

foreach ( XmlNode xmlTag in
ItemTag.ChildNodes)

{

// check the tag name if
corresponds to one of the specified,

// then in
the corresponding property of the object is written the contents of the tag

switch (xmlTag.Name)

{
case "title" :

{

this .Title = xmlTag.InnerText;

break ;
}
case
"Description" :

{
this .Description = xmlTag.InnerText;

break ;

}

case
"Link" :

{

this .Link
= xmlTag.InnerText;

break ;

}

}

}

}

Oh by the way since we work with <font color = "# 2B91AF"
face = "Courier New" size = "2"> XmlNode, you need to enable
corresponding assembly in <font color = "# 0000ff" face = "Courier New"
size = "2"> using section:
using
System.Xml;

Rssitems


This class we have is a list of all feed entries. We will implement it
through generics, namely my favorite generic class
List
And I like this generic because it provides very convenient methods of working with
arrays of data.
Add a new class to the project and name it RssItems . We get the following:
using
System;
using System.Collections.Generic;

using System.Text;
namespace
RssReader

{

class rssItems

{

}

}

Next we inherit RssItems from
List , instead of T specifying
the type whose objects will be stored in the list. At the same time override the method Contains,
to determine the existence of an entry in the list by its title.
///

/// Check for the existence of the specified
item in list
///

/// object to compare

/// true if there is an object in the list, otherwise
false

new
public
bool Contains ( RssItem Item)

{

foreach ( RssItem itemForCheck in this )

{

//
Compare record headers

if
(Item.Title == itemForCheck.Title)

{

// found
coincidence. return the truth

return
true ;

}

}

//
no matches found. we return the box

return
false ;

}

It would also be not bad to be able to catch the record of interest from the list.
using her title. To do this, we write another method similar to the Contains method:
///

/// Get an entry from the list by its
header
///

/// record title

/// If the record exists, it is returned
otherwise, it returns null
public RssItem GetItem ( String Title)

{ foreach ( RssItem itemForCheck in this )

{

//
Compare the record header with the query.

if
(Item.Title == Title)

{

// found a match.
return the found record

return
itemForCheck;

}

}

// no matches found.

return null ;

}

Rssfeed


So we got to the main class of our reader.
This class will store channel information. According to the specification of rss 2.0 to mandatory
Channel elements include: < title > - title
channel through which people will refer to the service; < link > is the URL of the website associated with the channel; < description > is a phrase or sentence to describe the channel.
Add a new class to the project again and call it RssFeed .
using
System;
using System.Collections.Generic;

using System.Text;


namespace RssReader

{
class RssFeed

{

}
}

Since all of the above channel properties are required, we need to add
them and in our class. We also add a property of type RssItems to store the list of channel entries:
class RssFeed

{
public String Title;
// channel header

public
String Description; //
description of the canal

public
String link; // link to
channel related website

public
RssItems Items; // list of channel entries

}

All that remains to be done now is to write a class constructor, which will be
receive, as a parameter, a link to the rss channel, and if the rss is really there
There is, fill the properties of the created object with data from rss (I hope the code
no questions arise, I tried to comment on it in detail):
///

/// Constructor for filling data
channel
///
/// Channel Address
public
RssFeed ( String Url)

{

//
We initialize the list of records

Items = new
RssItems ();

// Create a reader to read Rss from
specified address

XmlTextReader
xmlTextReader = New XmlTextReader (Url);

// create a new xml document to write to it
RSS feed

XmlDocument xmlDoc = New
XmlDocument ();

try

{

// load the RSS into the document using the reader

xmlDoc.Load (xmlTextReader);

// close reader for
uselessness

xmlTextReader.Close ();

//
since all the RSS feed information is written between the tags,
// ship we get this thread.

XmlNode channelXmlNode = xmlDoc.GetElementsByTagName ( "channel" ) [0];

// if a
the branch exists, we begin to flood the properties of the object
// data from a branch

if
(channelXmlNode! = null )

{

// iterate all descendants of the tag

foreach ( XmlNode
channelNode in channelXmlNode.ChildNodes)

{

// if the name of the descendant tag is of interest to us, then
write his data

// to a specific
object property

switch
(channelNode.Name)

{

case
"Title" :

{

Title =
channelNode.InnerText;

break ;

}

case "description" :

{

Description =
channelNode.InnerText;

break ;

}

case "link" :

{

Link = channelNode.InnerText;

break ;

}

case "item" : // if the name of the tag being checked is item, then

{

// create a new tag from this
write object

Rss <span
lang = "en-us"> Item channelItem = new
RssItem (channelNode);

// and add it to
list of channel entries

Items.Add (channelItem);

break ;

}

}

}

}

else
//
if no tag is found in the resulting file, then we throw an exception

{

throw New Exception ( "Error in XML. Channel description not found!" );

}

}

// If the channel url is not specified correctly, then throw it away.
source unreachable exception
catch
(System.Net.WebException ex)

{

if (ex.Status
== System.Net.WebExceptionStatus.NameResolutionFailure)

throw new Exception ( "Unable to connect to the specified source. \ r \ n" +
Url);

else throw
ex;

}

// if the RSS address was specified
local path that does not exist yet,

//
then throw the corresponding exception

catch
(System.IO.FileNotFoundException)

{

throw New
Exception ( "File" + Url + "
not found! ” );

}

// well and lastly, we catch everything
the remaining exceptions, and pass them on as is

catch (Exception ex)

{

throw
ex;

}

finally

{

//
close the reader

xmlTextReader.Close ();

}

}

Final stage


Now, all that's left to do is write the code for the click event handlers.
“update” buttons and selecting an item in ListView , as well as adding a global variable CurrentFeed, in which the loaded channel will be stored:

//
Global variable storing channel data

Rssfeed
CurrentFeed;


// processing of clicking on the "Update" button
private void btRefresh_Click ( object sender, EventArgs
e)

{

// Check if the address is set

if (! String .IsNullOrEmpty (tbUrl.Text))

{

// Clear the ListView before adding new data

lvNews.Clear ();

// Initialize the channel

CurrentFeed = new RssFeed (tbUrl.Text);

foreach ( Rss <span
lang = "en-us"> Item feedItem in
CurrentFeed.Items)

{

// create an item to display in the ListView

ListViewItem listViewItem = new ListViewItem (feedItem.Title);

// set his name

listViewItem.Name = feedItem.Title;

// put it in the listview

lvNews.Items.Add (listViewItem);

}

}

}

// Processing the change of item selection in the ListView
private void lvNews_SelectedIndexChanged ( object sender, EventArgs
e)

{

// get the news associated with the selected ListViewItem

if (lvNews.SelectedItems.Count> 0
&& // check that something is really selected

CurrentFeed! = Null
&& // check that the channel is initialized

CurrentFeed.Items.Count> 0
// check the existence of records in the channel

)

{

// display the full text of the selected entry

wbDescription.DocumentText =
CurrentFeed.Items.GetItem (lvNews.SelectedItems [0] .Text) .Description;
}
}

Conclusion


As a result, we got a simple RSS reader that can read standard 2.0 feeds.
In the next article I will try to tell you how to make our classes more
universal, as well as you can organize the storage of the history of visited
tapes.
Download the source of the written reader here .

PS: constructive criticism, as well as suggestions and suggestions are welcome.

Ramil Aliyakberov aka R @ Me0!

* All source codes were highlighted using Source Code Highlighter .

Source: https://habr.com/ru/post/27443/


All Articles