Reid Carlberg

Connected Devices, salesforce.com & Other Adventures

Salesforce Apex RSS Reader Featuring XMLStreamReader

0

For reasons I won’t go into (but which are probably obvious when you look at the code) I needed a simple way of importing RSS feeds into Salesforce. Although I have seen others, I decided to create a new one using XMLStreamReader that includes test coverage and which is installable via an unmanaged package.

Why XMLStreamReader¬†instead of the oft used XMLNode? Well, in the case of RSS, XMLStreamReader is great because it’s a read-only interface, which is all I want to do. This keeps everything super fast and efficient, and pretty easy to test.

The heavy lifting is done in the BlogLog_RssReader class. As a developer, you simply send the raw text representation of the RSS XML into the read method, and it returns a List of Blog_Entry__c objects.

Here’s the meat:

    public List<Blog_Entry__c> read(String document) {
        List<Blog_Entry__c> ret = new List<Blog_Entry__c>();
        boolean isSafeToGetNextXmlElement = true;

        XmlStreamReader reader = new XmlStreamReader(document);

        while(isSafeToGetNextXmlElement) {
            if (reader.getEventType() == XmlTag.START_ELEMENT) {
                System.debug('^^^^' + reader.getLocalName());
                if ('item' == reader.getLocalName()) {
                    Blog_Entry__c item = parseItem(reader);
                    ret.add(item);
                }
            }
            // Always use hasNext() before calling next() to confirm 
            // that we have not reached the end of the stream
            if (reader.hasNext()) {
                reader.next();
            } else {
                isSafeToGetNextXmlElement = false;
                break;
            }
        }        

        return ret;
    }

    Blog_Entry__c parseItem(XmlStreamReader reader) {

        Blog_Entry__c ret = new Blog_Entry__c();
        boolean isSafeToGetNextXmlElement = true;

        while(isSafeToGetNextXmlElement) {
            if (reader.getEventType() == XmlTag.END_ELEMENT &&
               'item' == reader.getLocalName()) {
                isSafeToGetNextXmlElement = false;  
                   break;
            }
            if (reader.getEventType() == XmlTag.START_ELEMENT) {
                System.debug('****' + reader.getLocalName() + '~~~~' + reader.getNamespace());
                if ('title' == reader.getLocalName() && reader.getNamespace() == null) {
                        String title = parseString(reader);
                        ret.Title__c = title;
                }
                if ('link' == reader.getLocalName() && reader.getNamespace() == null) {
                        String link = parseString(reader);
                        ret.Link__c = link;
                }
                if ('origLink' == reader.getLocalName()) {
                        String link = parseString(reader);
                        ret.Link__c = link;
                }
                if ('creator' == reader.getLocalName() ) {
                        String author = parseString(reader);
                        ret.Author__c = author;
                } 
                if ('category' == reader.getLocalName() ) {
                        String category = parseString(reader);
                    if (ret.Category__c != null) {
                        ret.Category__c = ret.Category__c + ', ' + category;
                    } else {
                        ret.Category__c = category;
                    }
                    if (ret.Category__c.length() > 250) {
                        ret.Category__c = ret.Category__c.substring(0,249);
                    }
                }  
                if ('pubDate' == reader.getLocalName() ) {
                        String pubDate = parseString(reader);
                        ret.Published__c = convertRSSDateStringToDate(pubDate);
                } 
                if ('description' == reader.getLocalName() ) {
                        String description = parseString(reader);
                        ret.Lead_Copy__c = description;
                }                 

            }
            // Always use hasNext() before calling next() to confirm 
            // that we have not reached the end of the stream
            if (reader.hasNext()) {
                reader.next();
            } else {
                isSafeToGetNextXmlElement = false;
                break;
            }
        }        

        return ret;

    }

    String parseString(XmlStreamReader reader) {
        String ret = '';

        boolean isSafeToGetNextXmlElement = true;
        while(isSafeToGetNextXmlElement) {
            System.debug('****EVENTTYPE' + reader.getEventType());
            if (reader.getEventType() == XmlTag.END_ELEMENT) {
                break;
            } else if (reader.getEventType() == XmlTag.CHARACTERS) {
                System.debug('****Characters |' + reader.getText() + '|');
                ret = ret + reader.getText();
            } else if (reader.getEventType() == XmlTag.CDATA) {
                System.debug('****CDATA');
                ret = reader.getText();
            }
            // Always use hasNext() before calling next() to confirm 
            // that we have not reached the end of the stream
            if (reader.hasNext()) {
                reader.next();
            } else {
                isSafeToGetNextXmlElement = false;
                break;
            }
        }
        return ret.trim();
    }

You get the idea. Read method takes the whole document and looks for an item. ParseItem looks for the individual fields I care about, and ParseString gets the code out of those fields. Good times.

Code is on Github. As always, you can get a free Developer Edition with a few quick clicks.

Improvements? Comments? Let me know.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: