function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
SalesforceLearnerSalesforceLearner 

Attempt to de-reference a null object when calling external URL.

I have end point url

http://proxy.abc.com/aproxy/rssFeed.jsp?rssUrl=http://news.abc.com/rss.jkl%3Fsection_id%4F5

when opened it is in the form of XML as shown below which displays news information.
<title>
<![CDATA[
ABCDEFGH
]]>
</title>
<link>
https://news.com
</link>
<description>
<![CDATA[ ]]>
</description>

I wrote below code to display on VF page but it is giving "Attempt to de-reference a null object" Error. When I debugged it is throwing error at RSS classDom.XMLNode rss = doc.getRootElement(); I dont no where I am making mistake.

Page :
<apex:page controller="RSSNewsReader" sidebar="false" showHeader="false" cache="false">


<apex:pageBlock id="rssBlock" tabStyle="Lead">


    <apex:pageBlockSection title="Channel" columns="2">
        <apex:pageBlockSectionItem >
            <apex:outputLabel value="title" />
            <apex:outputText value="{!RSSFeed.title}" />
        </apex:pageBlockSectionItem>
        <apex:pageBlockSectionItem >
            <apex:outputLabel value="link" />
            <apex:outputText value="{!RSSFeed.link}" />
        </apex:pageBlockSectionItem>
        <apex:pageBlockSectionItem >
            <apex:outputLabel value="description" />
            <apex:outputText value="{!RSSFeed.description}" />
        </apex:pageBlockSectionItem>
        <apex:pageBlockSectionItem >
            <apex:outputLabel value="category" />
            <apex:outputText value="{!RSSFeed.category}" />
        </apex:pageBlockSectionItem>
       </apex:pageBlockSection>


</apex:pageBlock>

</apex:page>

Controller :
public class RSSNewsReader {

    public String rssQuery {get;set;}
    private String rssURL {get;set;}

    public RSSNewsReader() {

        rssURL = 'http://news.abc.com/rss.jkl%3Fsection_id%4F5';
        rssQuery = ''; //default on load

    }

    public RSS.channel getRSSFeed() {
        return RSS.getRSSData(rssURL);
    }


}
class:
 
public class channel {
        public String title {get;set;}
        public String link {get;set;}
        public String description {get;set;}
        public String author {get;set;}
        public String category {get;set;}
        public String copyright {get;set;}
        public String docs {get;set;}
        public RSS.image image {get;set;}
        public list<RSS.item> items {get;set;}
        public channel() {
            items = new list<RSS.item>();
        }
    }

    public class image {
        public String url {get;set;}
        public String title {get;set;}
        public String link {get;set;}
    }

    public class item {
        public String title {get;set;}
        public String guid {get;set;}
        public String link {get;set;}
        public String description {get;set;}
        public String pubDate {get;set;}
        public String source {get;set;}
        public Date getPublishedDate() {
            Date result = (pubDate != null) ? Date.valueOf(pubDate.replace('T', ' ').replace('Z','')) : null;
            return result;
        }
        public DateTime getPublishedDateTime() {
            DateTime result = (pubDate != null) ? DateTime.valueOf(pubDate.replace('T', ' ').replace('Z','')) : null;
            return result;
        }
    }

    public static RSS.channel getRSSData(String FeedURL) {

        HttpRequest req = new HttpRequest();
        req.setEndpoint(FeedURL);
        req.setMethod('GET');

        Dom.Document doc = new Dom.Document();
        Http h = new Http();


        Dom.XMLNode rss = doc.getRootElement();
        //first child element of rss feed is always channel
        Dom.XMLNode channel = rss.getChildElements()[0];

        RSS.channel result = new RSS.channel();

        list<RSS.item> rssItems = new list<RSS.item>();

        //for each node inside channel
        for(Dom.XMLNode elements : channel.getChildElements()) {
            if('title' == elements.getName()) {
                result.title = elements.getText();
            }
            if('link' == elements.getName()) {
                result.link = elements.getText();
            }
            if('description' == elements.getName()) {
                result.description = elements.getText();
            }
            if('category' == elements.getName()) {
                result.category = elements.getText();
            }
            if('copyright' == elements.getName()) {
                result.copyright = elements.getText();
            }
            if('docs' == elements.getName()) {
                result.docs = elements.getText();
            }
            if('image' == elements.getName()) {
                RSS.image img = new RSS.image();
                //for each node inside image
                for(Dom.XMLNode xmlImage : elements.getChildElements()) {
                    if('url' == xmlImage.getName()) {
                        img.url = xmlImage.getText();
                    }
                    if('title' == xmlImage.getName()) {
                        img.title = xmlImage.getText();
                    }
                    if('link' == xmlImage.getName()) {
                        img.link = xmlImage.getText();
                    }
                }
                result.image = img;
            }

            if('item' == elements.getName()) {
                RSS.item rssItem = new RSS.item();
                //for each node inside item
                for(Dom.XMLNode xmlItem : elements.getChildElements()) {
                    if('title' == xmlItem.getName()) {
                        rssItem.title = xmlItem.getText();
                    }
                    if('guid' == xmlItem.getName()) {
                        rssItem.guid = xmlItem.getText();
                    }
                    if('link' == xmlItem.getName()) {
                        rssItem.link = xmlItem.getText();
                    }
                    if('description' == xmlItem.getName()) {
                        rssItem.description = xmlItem.getText();
                    }
                    if('pubDate' == xmlItem.getName()) {
                        rssItem.pubDate = xmlItem.getText();
                    }
                    if('source' == xmlItem.getName()) {
                        rssItem.source = xmlItem.getText();
                    }
                }
                //for each item, add to rssItem list
                rssItems.add(rssItem);
            }

        }
        //finish RSS.channel object by adding the list of all rss items
        result.items = rssItems;

        return result;

    }



}


 
Best Answer chosen by SalesforceLearner
pconpcon
The problem now is that your are using a document that you created, and not one that you parsed from the URL.  Line 41-49 should read
 
public static RSS.channel getRSSData(String FeedURL) {
    Http h = new Http();
    HttpRequest req = new HttpRequest();
    req.setEndpoint(FeedURL);
    req.setMethod('GET');

    HttpResponse res = h.send(req);
    Dom.Document doc = res.getBodyDocument();
    Dom.XMLNode rss = doc.getRootElement();

 

All Answers

pconpcon
If I goto the URL you provided (below) I get a DNS error because it cannot find that hostname.
 
http://news.abc.com/rss.jkl%3Fsection_idO5

The reason you are getting the Null Pointer Exception (NPE) is because there is nothing in the content body to parse.  If these URLs exist but are behind a firewall / VPN you will not be able to use them from Salesforce.
SalesforceLearnerSalesforceLearner

Thanks for the reply, but I tried with "http://feeds.abcnews.com/abcnews/topstories"  and it has content in the body but still facing the same error.
pconpcon
The problem now is that your are using a document that you created, and not one that you parsed from the URL.  Line 41-49 should read
 
public static RSS.channel getRSSData(String FeedURL) {
    Http h = new Http();
    HttpRequest req = new HttpRequest();
    req.setEndpoint(FeedURL);
    req.setMethod('GET');

    HttpResponse res = h.send(req);
    Dom.Document doc = res.getBodyDocument();
    Dom.XMLNode rss = doc.getRootElement();

 
This was selected as the best answer
pconpcon
It actually turns out that the XMLNode doesn't handle CDATA [1].  You can remove it by doing the following:
 
public static RSS.channel getRSSData(String FeedURL) {
    Http h = new Http();
    HttpRequest req = new HttpRequest();
    req.setEndpoint(FeedURL);
    req.setMethod('GET');

    HttpResponse res = h.send(req);

    String xml = res.getBody();

    String encoded = EncodingUtil.urlEncode(xml,'UTF-8');
    encoded = encoded.replaceAll('%3C%21%5BCDATA%5B',''); // i.e. '<![CDATA['
    encoded = encoded.replaceAll('%5D%5D%3E',''); // i.e. ']]>'
    xml = EncodingUtil.urlDecode(encoded,'UTF-8');

    Dom.Document doc = new Dom.Document();
    doc.load(xml);
    Dom.XMLNode rss = doc.getRootElement();

You'll also want to actually show the items in your Visualforce page:
 
<apex:page controller="RSSNewsReader" sidebar="false" showHeader="false" cache="false">  
    <apex:pageBlock id="rssBlock" tabStyle="Lead">
        <apex:pageBlockSection title="Channel" columns="2">
            <apex:pageBlockSectionItem >
                <apex:outputLabel value="title" />
                <apex:outputText value="{!RSSFeed.title}" />
            </apex:pageBlockSectionItem>
            <apex:pageBlockSectionItem >
                <apex:outputLabel value="link" />
                <apex:outputText value="{!RSSFeed.link}" />
            </apex:pageBlockSectionItem>
            <apex:pageBlockSectionItem >
                <apex:outputLabel value="description" />
                <apex:outputText value="{!RSSFeed.description}" />
            </apex:pageBlockSectionItem>
            <apex:pageBlockSectionItem >
                <apex:outputLabel value="category" />
                <apex:outputText value="{!RSSFeed.category}" />
            </apex:pageBlockSectionItem>
        </apex:pageBlockSection>
        <apex:pageBlockSection title="Items">
            <apex:pageBlockTable value="{!RSSFeed.items}" var="item">
                <apex:column value="{!item.title}" />
            </apex:pageBlockTable>
        </apex:pageBlockSection>
    </apex:pageBlock>   
</apex:page>

[1] http://salesforce.stackexchange.com/questions/34692/how-to-convert-an-dom-xmlnode-to-its-string-representation-in-order-to-get-cdata