1

I am building an RSS feed parser using XmlPullParser in Android Studio. I would like to display the feed images in my app, however I am having trouble retrieving the url attribute value in the <media:thumbnail> tag. As a note: I am only retrieving things inside <item>. After doing considerable research, I learned it has something to do with XML namespaces. I setNamespaceAware(true), with no luck. All my other elements are being retrieved properly, but I keep getting null for my imageLink variable. I have also tried setting

else if (name.equalsIgnoreCase("media:thumbnail")) {
    imageLink = xmlPullParser.getAttributeValue(null, "url");
}

to "media:thumbnail" or "thumbnail".

Link to the RSS feed: https://www.goal.com/feeds/en/news

A snippet of the XML code:

<item>
  <title>
    <![CDATA[Mexico boss Martino responds after USMNT's Berhalter calls on referee to take control of Gold Cup final]]>
  </title>
  <pubDate>Sat, 31 Jul 2021 20:30:03 GMT</pubDate>
  <link>
  <![CDATA[https://www.goal.com/en/news/mexico-boss-martino-responds-after-usmnts-berhalter-calls-on/1h5obazjxkl3c1hrevc53ovtfy]]>
  </link>
  <guid isPermaLink="false">urn:perform:article:1h5obazjxkl3c1hrevc53ovtfy</guid>
  <description>
    <![CDATA[The two managers went back and forth when discussing each team's ability to manipulate the match official]]>
  </description>
  <category>@Geo; Everywhere</category>
  <category>@Targeting</category>
  <category>@Google Newsstand</category>
  <category>@Apple News</category>
  <category>@News2021</category>
  <category>@News - original</category>
  <category>@Manager/coach quotes</category>
  <media:content url="http://images.daznservices.com/di/library/GOAL/36/54/martino-berhalter-split_1bbaicsveobrw1xcg0fsjk04ra.png?t=43319131" type="image/jpeg" />
  <media:thumbnail url="http://images.daznservices.com/di/library/GOAL/36/54/martino-berhalter-split_1bbaicsveobrw1xcg0fsjk04ra.png?t=43319131" />
  <media:content url="http://images.daznservices.com/di/library/GOAL/36/54/martino-berhalter-split_1bbaicsveobrw1xcg0fsjk04ra.png?t=43319131" type="image/jpeg" />
  <media:thumbnail url="http://images.daznservices.com/di/library/GOAL/36/54/martino-berhalter-split_1bbaicsveobrw1xcg0fsjk04ra.png?t=43319131" />
  <media:content url="http://images.daznservices.com/di/library/GOAL/36/54/martino-berhalter-split_1bbaicsveobrw1xcg0fsjk04ra.png?t=43319131" type="image/jpeg" />
  <media:thumbnail url="http://images.daznservices.com/di/library/GOAL/36/54/martino-berhalter-split_1bbaicsveobrw1xcg0fsjk04ra.png?t=43319131" />
  <media:content url="http://images.daznservices.com/di/library/GOAL/36/54/martino-berhalter-split_1bbaicsveobrw1xcg0fsjk04ra.png?t=43319131" type="image/jpeg" />
  <media:thumbnail url="http://images.daznservices.com/di/library/GOAL/36/54/martino-berhalter-split_1bbaicsveobrw1xcg0fsjk04ra.png?t=43319131" />
  <df:language>en</df:language>
  <dc:language>en</dc:language>
  <df:authors/>
  <dc:creator/>
</item>

This is my code

public List<RssFeedModel> parseFeed(InputStream inputStream) throws XmlPullParserException, IOException {
    String title = null;
    String link = null;
    String description = null;
    String imageLink = null;
    boolean isItem = false;
    List<RssFeedModel> items = new ArrayList<>();

    try {
        XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
        factory.setNamespaceAware(true);
        XmlPullParser xmlPullParser = factory.newPullParser();
        xmlPullParser.setInput(inputStream, "UTF-8");

        while (xmlPullParser.next() != XmlPullParser.END_DOCUMENT) {
            int eventType = xmlPullParser.getEventType();

            String name = xmlPullParser.getName();
            if (name == null)
                continue;
            if (eventType == XmlPullParser.END_TAG) {
                if (name.equalsIgnoreCase("item")) {
                    isItem = false;
                }
                continue;
            }
            if (eventType == XmlPullParser.START_TAG) {
                if (name.equalsIgnoreCase("item")) {
                    isItem = true;

                    continue;
                }
            }
            Log.d("MyXmlParser", "Parsing name ==> " + name);
            String result = "";
            if (xmlPullParser.next() == XmlPullParser.TEXT) {
                result = xmlPullParser.getText();
                xmlPullParser.nextTag();
            }

            if (name.equalsIgnoreCase("title")) {
                title = result;
            } else if (name.equalsIgnoreCase("link")) {
                link = result;
            } else if (name.equalsIgnoreCase("description")) {
                description = result;
            } else if (name.equalsIgnoreCase("thumbnail")) {//for image
                imageLink = xmlPullParser.getAttributeValue(null, "url");
            }

            if (title != null && link != null && description != null) {
                if (isItem) {
                    RssFeedModel item = new RssFeedModel(title, link, description, imageLink);
                    items.add(item);
                } else {
                    mFeedTitle = title;
                    mFeedLink = link;
                    mFeedDescription = description;
                }
            }
        }
        return items;
    } finally {
        inputStream.close();
    }
}
dxp99
  • 13
  • 4
  • 1
    It's 2021. Life is too short to use `XmlPullParser`. Use [Moshi](https://github.com/square/moshi). If you insist upon using `XmlPullParser`, then I think you need to be passing the namespace URI as [the first parameter to `getAttributeValue()`](https://developer.android.com/reference/org/xmlpull/v1/XmlPullParser?hl=en#getAttributeValue(java.lang.String,%20java.lang.String)), since you have enabled namespaces. `"http://search.yahoo.com/mrss/"` appears to be the URI, based upon the full XML document. – CommonsWare Jul 31 '21 at 21:53
  • Thanks for your reply. I passed the namespace URI to getAttributeValue() but that didn't work either. This is for an assignment which specifically requires XmlPullParser, but I will keep Moshi in mind for future work. Much appreciated again. – dxp99 Aug 01 '21 at 01:31

1 Answers1

0

Just answering my own question for future reference:

public List<RssFeedModel> parseFeed(InputStream inputStream) throws XmlPullParserException, IOException {

/**
 * Declares the variables to hold article title, link and description
 * Declares List to hold all items once parsed
 */
String title = null;
String link = null;
String description = null;
String imageLink = null;
List<RssFeedModel> items = new ArrayList<>();

/**Logic for parsing through the XML*/
try {
    XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
    factory.setNamespaceAware(true);
    XmlPullParser xpp = factory.newPullParser();
    xpp.setInput(inputStream, null);

    /**Retrieves eventType (START_DOCUMENT, START_TAG, END_DOCUMENT)*/
    int eventType = xpp.getEventType();
    /**Only checks items that are within the <item></item> tags*/
    boolean insideItem = false;

    while (eventType != XmlPullParser.END_DOCUMENT) {
        if (eventType == XmlPullParser.START_TAG) {
            if (xpp.getName().equalsIgnoreCase("item")) {
                insideItem = true;
            } else if (xpp.getName().equalsIgnoreCase("title")) {
                if (insideItem) {
                    title = xpp.nextText();
                }
            } else if (xpp.getName().equalsIgnoreCase("description")) {
                if (insideItem) {
                    description = xpp.nextText();
                }
            } else if (xpp.getName().equalsIgnoreCase("link")) {
                if (insideItem) {
                    link = xpp.nextText();
                }
            } else if (xpp.getName().equalsIgnoreCase("thumbnail")) {
                if (insideItem) {
                    imageLink = xpp.getAttributeValue(null, "url");
                }
            }

            /**Once cursor arrives at the END_TAG, save parsed items into List*/
        } else if (eventType == XmlPullParser.END_TAG) {
            if(xpp.getName().equalsIgnoreCase("item")){
                if (insideItem) {
                    RssFeedModel item = new RssFeedModel(title, link, description, imageLink);
                    items.add(item);
                }else if (xpp.getName().equalsIgnoreCase("channel")){
                    insideItem = false;
                }
            }
        }
        eventType = xpp.next();
    }

    return items;
} finally {
    inputStream.close();
}

}

dxp99
  • 13
  • 4