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 )

Facebook photo

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

Connecting to %s

%d bloggers like this: