BREW RSS Reader - 5 / 9 -
Analyze RSS Data
Data Structure of RssReader
// RSSItem structure ( one item )
SFMTYPEDEFSTRUCT(RSSItem)
struct RSSItem {
SFXAnsiString title;
SFXAnsiString description;
SFXAnsiString topic;
SFXDate date; // For saving date in format of SFXDate
Bool alreadyRead; // Flag showing whether it has been read or not
RSSItem(SFXAnsiStringConstRef rsstitle,
SFXAnsiStringConstRef rssdescription,
SFXAnsiStringConstRef rsstopic, SFXDateConstRef rssdate,
Bool rssalreadyRead = false);
};
// RSSFeed class ( one RSS feed )
SFMTYPEDEFCLASS(RSSFeed)
class RSSFeed {
public:
SFXAnsiString _title; // Site title
SFXAnsiString _url; // Site URL
SFXDate _date; // Latest updated date
private:
SFXAnsiString _filename; // Name of file to save RSS data
SFXList<RSSItemPtr> _itemList; // List of RSS items ... *
public:
RSSFeed(SFXAnsiStringConstRef title,
SFXAnsiStringConstRef url, SFXDateConstRef date = SFXDate());
~RSSFeed(Void);
SFCError Parse(SFXAnsiStringConstRef xml);
SFCError SaveToFile(Void);
Void LoadFromFile(Void);
Bool Find(RSSItemConstRef item);
RSSItemPtr GetItem(SInt32 index) { return _itemList.Get(index); }
SFXAnsiStringConstRef GetFilename(Void) { return _filename; }
Void SetFilename(SFXAnsiStringConstRef filename) { _filename = filename; }
SInt32 GetSize(Void) { return _itemList.GetSize(); }
friend class RSSFeedList;
};
// RSSFeedList class ( list of RSS feeds )
SFMTYPEDEFCLASS(RSSFeedList)
class RSSFeedList {
private:
SFXArray<RSSFeedPtr> _feedArray; // array of RSS feeds
public:
~RSSFeedList(Void);
Bool Add(RSSFeedPtr feed);
SFCError SaveToFile(Void);
Void LoadFromFile(Void);
SInt32 GetSize(Void) { return _feedArray.GetSize(); }
SInt32 IndexOf(RSSFeedPtr item) { return _feedArray.IndexOf(item); }
RSSFeedPtr operator[](SInt32 index) { return _feedArray[index]; }
};
* "SFXList<RSSItemPtr> _itemList;"
As elements of SophiaFramework UNIVERSE Collection class should not be bigger than 4 bytes in size, SFXList is used to save the data of an RSSItem through an RSSItemPtr.
Append Item to RSSItemPtr
RSSItemPtr item;
// generate an RSS item by using new
item = ::new RSSItem("title", "desc", "topic", SFXDate::CurrentDate());
// append the item
_itemList.Append(item);
Refer to the Item of the RSSItemPtr
// refer to the first item _itemList.Get(0);
Write the Variables of RSSFeed onto File
// data format for saving RSSFeed class as file title<>description<>topic<>date<>alreadyRead\r\n title<>description<>topic<>date<>alreadyRead\r\n ...
The variable date is an integer of type UInt32. As for alreadyRead, it will be 1 if true and 0 if false.
#define DIRECTORY_NAME "/data"
#define DELIMITER_STR "<>"
#define DELIMITER_LEN 2
SFCError RSSFeed::SaveToFile(Void)
{
SFCError error;
SFXPath temp;
SFXFile file;
SFXAnsiStringStreamWriter writer;
RSSItemPtr item;
SFXPath filename(DIRECTORY_NAME + _filename);
SFXPath dir(DIRECTORY_NAME);
// Get path for temporary saving
error = SFXFile::GetTemporaryPath(dir, &temp);
if (error == SFERR_NO_ERROR) {
// open file
error = file.OpenReadWrite(temp);
if (error == SFERR_NO_ERROR) {
// Get the writing stream
error = file.GetStreamWriter(4096, &writer);
if (error == SFERR_NO_ERROR) {
// Get iterator
SFXList<RSSItemPtr>::Iterator
itor(_itemList.GetFirstIterator());
while (itor.HasNext()) {
// Write RSSItem onto file
item = itor.GetNext();
writer << item->title << DELIMITER_STR
<< item->description << DELIMITER_STR
<< item->topic << DELIMITER_STR
<< SFXAnsiString::Format("%u",
item->date.AsUInt32()) << DELIMITER_STR
<< ((item->alreadyRead) ? "1"
: "0") << "\r\n";
// The data is actually written
//when Flush() is called
writer.Flush();
}
}
file.Close();
}
}
if (error == SFERR_NO_ERROR) {
// Delete file
SFXFile::Remove(filename);
// Rename file
error = SFXFile::Rename(temp, filename);
}
return error;
}
SFXFile::GetTemporaryPath
You should get a temporary file name by calling SFXFile::GetTemporaryPath(). Once you have finished writing data in the temporary file, change its name to the proper one.
This system is safe even if no data is writen in the temporary file.
Read from File
Void RSSFeed::LoadFromFile(Void)
{
SFCError error;
SFXFile file;
SFXAnsiStringStreamReader reader;
SFXAnsiString string;
SFXPath path(DIRECTORY_NAME + _filename);
UInt32 size;
SFXFile::GetSize(path, &size); // Get file size
error = file.OpenReadOnly(path); // Open file
if (error == SFERR_NO_ERROR) { // if open succeed
// Get reading stream
error = file.GetStreamReader(size + 1, &reader);
if (error == SFERR_NO_ERROR) {
// Read from file
reader.Fetch();
// Save to string
reader.ReadSFXAnsiString(&string);
SInt32 c1 = 0;
SInt32 c2, c3, c4, c5, c6;
while (true) {
// Search for first line delimiter (end of line)
c2 = string.IndexOf(DELIMITER_STR, c1);
if (c2 < 0) { // If not found, there is no line
break;
}
c3 = string.IndexOf(DELIMITER_STR, c2 + 1);
c4 = string.IndexOf(DELIMITER_STR, c3 + 1);
c5 = string.IndexOf(DELIMITER_STR, c4 + 1);
c6 = string.IndexOf('\n', c5) + 1;
SFXAnsiString dateNumber = string.Substring(c4
+ DELIMITER_LEN, c5);
SFXDate date;
// Get the date in a number type
date.Set(dateNumber.AsUInt32());
RSSItemPtr item = new RSSItem(string.Substring(c1, c2),
string.Substring(c2 + DELIMITER_LEN, c3),
string.Substring(c3 + DELIMITER_LEN, c4), date,
string.Substring(c5 + DELIMITER_LEN, c6).Trim()
== "1");
// Append to the list
if (_itemList.Append(item) != SFERR_NO_ERROR) {
::delete item;
break;
}
c1 = c6;
}
}
file.Close();
}
return;
}
* In file processing, registering a callback function is not needed because Fetch() will be finished immediately.
Analyzing the RSS Data
Here, the SFXXMLDOMParser for DOM structure is used as an XML parser.
You should get the XML document analyzed by the Parse() function of SFXXMLDOMParser using GetDocument().
When processing nodes, use GetFirstChild() to get the first child node, GetNextSibling() to get the sibling nodes, GetNodeName() to get the node names etc.
SFCError RSSFeed::Parse(SFXAnsiStringConstRef xml)
{
SFCError error;
SFXXMLDOMParser parser;
SFXXMLDocumentPtr root;
SFXXMLNodePtr child;
SFXAnsiString title;
SFXAnsiString description;
SFXDate date;
RSSItemPtr item;
SInt32 listcount;
SInt32 count = 0;
SFXAnsiString temp;
// Analyze XML document
error = parser.Parse(xml);
// If parse failed
if (error != SFERR_NO_ERROR) return SFERR_FAILED;
// Get the root
root = parser.GetDocument();
if (root == null) return SFERR_FAILED;
// Search for title tag under channel tag
SFXList<SFXXMLNodePtr>* list = root->GetElementsByTagName("channel");
if (list != null && list->GetSize() > 0)
{
child = list->Get(0);
for (child = child->GetFirstChild() ;
child != null && error == SFERR_NO_ERROR ;
child = child->GetNextSibling())
{
// If title tag
if (SFXAnsiString(child->GetNodeName()) == "title")
{
temp = child->GetText();
if (_title.IsEmptyCString())
{
error = SFXTextEncoding::UTF8ToShiftJIS(temp, &_title);
}
}
else if (SFXAnsiString(child->GetNodeName()) == "dc:date")
{
date.Parse("YYYY-MM-DD%Thh:mm:ss+",
child->GetText());
}
}
// For each item tag
SFXList<SFXXMLNodePtr>* list = root->GetElementsByTagName("item");
if (list != null && list->GetSize() > 0)
{
for (listcount=0;
listcount < (list->GetSize());
listcount++)
{
child = list->Get(listcount);
for (child = child->GetFirstChild() ;
child != null && error == SFERR_NO_ERROR ;
child = child->GetNextSibling())
{
// If title tag
if (SFXAnsiString(child->GetNodeName()) == "title")
{
// Get text node
temp = child->GetText();
// Convert UTF-8 into Shift_JIS
error = SFXTextEncoding::UTF8ToShiftJIS(temp, &title);
}
// If description tag
else if (SFXAnsiString(child->GetNodeName()) == "description")
{
// Get text node
temp = child->GetText();
// Convert UTF-8 into Shift_JIS
error = SFXTextEncoding::UTF8ToShiftJIS(temp, &description);
}
// If dc: date tag
else if (SFXAnsiString(child->GetNodeName()) == "dc: date")
{
// Convert string into date
date.Parse("YYYY-MM-DD%Thh:mm:ss+",
child->GetText());
}
}
item = ::new RSSItem(title, description, date);
if (item != null)
{
// If not duplicated
if (!Find(*item))
{
// Insert item
error = _itemList.Insert(count, item);
if (error == SFERR_NO_ERROR)
{
++count;
}
else
{
::delete item;
}
}
else
{
::delete item;
}
}
else
{
error = SFERR_NO_MEMORY;
}
}
}
}
else
{
TRACE ("list empty");
}
// Error
if (error != SFERR_NO_ERROR)
{
_title = "Failed";
}
SFXHelper::dbgprintf("[SGXAWSParser] ParseXML END %d", error);
if (error == SFERR_NO_ERROR)
{
// Save to file
error = RSSFeed::SaveToFile();
}
return error;
}







