Home > Products > SophiaFramework UNIVERSE > Tutorial > RSS Reader > - 5 / 9 -

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;
}

Go back  1   2   3   4   5   6   7   Apdx1   Apdx2  Next page