1

I am making a very simple app with an RSS reader. The reader works great, but it's only giving me the title, and i want the description too. I'am very new to android, and I have tried a lot of things, but I can't get it to work. I've found a lot of parsers but they are to complicated for me to understand, so I was hoping to find a simple solution, since it's only title and description i want. Can anyone help me?

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class NyhedActivity extends Activity {
    String streamTitle = "";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.nyheder);

        TextView result = (TextView)findViewById(R.id.result);

           try {
       URL rssUrl = new URL("http://tv2sport.dk/rss/*/*/*/248/*/*");
       SAXParserFactory mySAXParserFactory = SAXParserFactory.newInstance();
       SAXParser mySAXParser = mySAXParserFactory.newSAXParser();
       XMLReader myXMLReader = mySAXParser.getXMLReader();
       RSSHandler myRSSHandler = new RSSHandler();
       myXMLReader.setContentHandler(myRSSHandler);
       InputSource myInputSource = new InputSource(rssUrl.openStream());
       myXMLReader.parse(myInputSource);

       result.setText(streamTitle);

      } catch (MalformedURLException e) {
       // TODO Auto-generated catch block
       e.printStackTrace();
       result.setText("Cannot connect RSS!");
      } catch (ParserConfigurationException e) {
       // TODO Auto-generated catch block
       e.printStackTrace();
       result.setText("Cannot connect RSS!");
      } catch (SAXException e) {
       // TODO Auto-generated catch block
       e.printStackTrace();
       result.setText("Cannot connect RSS!");
      } catch (IOException e) {
       // TODO Auto-generated catch block
       e.printStackTrace();
       result.setText("Cannot connect RSS!");
      }


       }

       private class RSSHandler extends DefaultHandler
       {
        final int stateUnknown = 0;
        final int stateTitle = 1;
        int state = stateUnknown;

        int numberOfTitle = 0;
        String strTitle = "";
        String strElement = "";

      @Override
      public void startDocument() throws SAXException {
       // TODO Auto-generated method stub
       strTitle = "Nyheder fra ";
      }

      @Override
      public void endDocument() throws SAXException {
       // TODO Auto-generated method stub
       strTitle += "";
       streamTitle = "" + strTitle;
      }

      @Override
      public void startElement(String uri, String localName, String qName,
        Attributes attributes) throws SAXException {
       // TODO Auto-generated method stub
       if (localName.equalsIgnoreCase("title"))
       {
        state = stateTitle;
        strElement = "";
        numberOfTitle++;
       }
       else
       {
        state = stateUnknown;
       }
      }

      @Override
      public void endElement(String uri, String localName, String qName)
        throws SAXException {
       // TODO Auto-generated method stub
       if (localName.equalsIgnoreCase("title"))
       {
        strTitle += strElement + "\n"+"\n";
       }
       state = stateUnknown;
      }

      @Override
      public void characters(char[] ch, int start, int length)
        throws SAXException {
       // TODO Auto-generated method stub
       String strCharacters = new String(ch, start, length);
       if (state == stateTitle)
       {
        strElement += strCharacters;
       }
      }
    }

}
2
  • The code you posted doesn't even attempt to read the description, it only contains code for the title. Commented Sep 16, 2011 at 7:45
  • I know that, that's because I've deleted the other code because it messed everything up. I am looking for a solution to make it right :) Commented Sep 16, 2011 at 8:30

3 Answers 3

1

I've never really used SAX, when it comes to parsing XML in Java. I allways use JDOM. It's simple and really easy to use.

To read a an XML-file with JDOM, you create a document and fill it using an InputStream and a SAXBuilder:

SAXBuilder builder = new SAXBuilder();
Document document = builder.builder( myInputStream );

In your posted case: myInputStream = url.openStream();

Then you need to fetch the root of the XML-document:

Element root = document.getRootElement();

Now it's very simple. Since I don't know the structure of the XML you're getting I'll just assume that it looks something like:

<rssfeed>
  <news>
    <title> Title </title>
    <description> Description </description>
  </news>
  <news>
    <title> ... </title>
    <description> ... </description>
  </news>
  <news>
    <title> ... </title>
    <description> ... </description>
  </news>
<rssfeed>

You can then list all elements of like this:

List<Element> news = root.getChildren( "news" );

Then you run through the list in a for-each loop, getting the title and description (Having a data-class to hold these information would be a help e.g. a News-class):

ArrayList<News> newsList = new ArrayList<News>();
for( Element child : news ) {
  News news = new News();
  news.setTitle( child.getChildText( "title" );
  news.setDescription( child.getChildText( "description" );
  newsList.add( news );
}

Now you have a list of news that you can play around with.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for your suggestion, but the answer is a little over my skill level at the moment. I found a lot of tutorials, but at the moment I don't understand every line of code, which make it very difficult for me to write my own parser class. The data I'm getting is: <item> <title> Title </title> <description> Description </description> </item>
The idea of using JDOM, is that the parse class has been written for you and all you need is to use it to get the data you need. You should be able to practically copy-paste my example once you've downloaded JDOM and added it to your projects buildpath. All you need to do is replace the string "news" with "item" and it should work.
Thanks. I will try that, even though I'm not sure I'am able to do it :)
1

Kano,

You can simplify your life and get top-notch performance by utilizing SJXP to write this RSS feed parser with (disclaimer: I am the author).

SJXP is a very-very thin abstraction layer that sits on top of the XML Pull Parsing API (Android provides its own so you only have the sjxp.JAR dependency, XPP3 for every other platform) and allows you to use XPath-like parsing rules for matching simple rules against certain places of a document and then telling the parsing what information you want from those locations.

I wrote an example Eclipse project for you that parses that TV2 Sports feed for you in 6 minutes (I'll link it at the bottom).

The main method looks like this so you get an idea of the flow:

public static void main(String[] args) throws IllegalArgumentException,
    XMLParserException, IOException {
// Location we want to parse.
URL feedURL = new URL("http://tv2sport.dk/rss/*/*/*/248/*/*");

// List we will hold all parsed stories in.
List<Item> itemList = new ArrayList<Item>();

// Get all the rules we will use to parse this file
IRule[] rules = createRules();

// Create the parser and populate it with the rules.
XMLParser<List<Item>> parser = new XMLParser<List<Item>>(rules);

// Parse the RSS feed.
parser.parse(feedURL.openStream(), itemList);

// Print the results.
System.out.println("Parsed " + itemList.size() + " RSS items.");

for (Item i : itemList)
    System.out.println("\t" + i);
}

You see the flow starts with creating our List to hold our Items in as we parse them from the doc. Then we get a set of IRule instances to give the parser, then create the parser and give it the rules to use while working.

We then invoke the parse method on the contents of the feed and pass it what is called a "user object", more specifically, just an instance of anything that we would like it to pass-through to the rules when they execute.

In this case, we want access to our List so we can add items to it, so we just pass that in and the parser passes it right through to our IRule logic when it executes so we can use it.

The Item class utilizes is just a simple POJO to hold the data and make printing look nice:

public class Item {
    public String title;
    public String description;

    @Override
    public String toString() {
        return "Item [title='" + title + "', description='" + description + "']";
    }
}

All the interesting stuff happens in your IRule where you define what kind of element you are targeting (character data, attribute data or just tag open/close events) and then override the appropriate method from the IRule interface to provide a handler that does something.

For example, here is the handler that parses the titles:

IRule<List<Item>> itemDescRule = new DefaultRule<List<Item>>(Type.CHARACTER, "/rss/channel/item/description") {
    @Override
    public void handleParsedCharacters(XMLParser<List<Item>> parser, String text, List<Item> userObject) {
        Item item = userObject.get(userObject.size() - 1);
        item.description = text;
    }
};

You see that you get given the parser instance itself (so you can trigger the 'stop' method if you want to end parsing early), you get the text that was the character data and you get that 'user object' which happened to be our list passed through to you.

We grab the item we are populating out of the list, give it the description and that's it. 2 lines of code.

There is another IRule that adds a new Item to the list every time an open-tag is encountered, that is what allows our subsequent rules like this one to just pop the end element off the list and populate it.

When you run the project, the output looks like this:

Parsed 50 RSS items.
    Item [title='Barcas bøddel beæret over Barca-føler', description='Tirsdag snød Thiago Silva Barcelona for tre point, da han headede AC Milans udligning i kassen i Champions League-kampens overtid.']
    Item [title='Guardiola: Pato hurtigere end Usain Bolt', description='FC Barcelona-træner, Josep Guardiola, er dybt imponeret af Milan-målscoreren Alexandre Patos hurtighed.']
    Item [title='Milan-profil: Vi kan nå semifinalen', description='Clarence Seedorf mener, at AC Milan kan nå semifinalerne i Champions League efter 2-2 i Barcelona.']
    <SNIP...>

You can download the entire Eclipse project I created for you here.

Hope that helps.

1 Comment

Thank you very much for all of your work. I will take a look at it tommorow. I found a solution for my problem, but I will take a look at your project and see if your solution is better :) I will leave a comment later.
0

I hope I can help you:

  @Override
  public void endElement(String uri, String localName, String qName)
    throws SAXException {
   // TODO Auto-generated method stub
   if (localName.equalsIgnoreCase("title"))
   {
    strTitle += strElement + "\n"+"\n";
   }
   else if (localName.equalsIgnoreCase("lead"))
   {
    lead += strElement + "\n"+"\n";
   }
  }

1 Comment

I've tried that, but it won't work. Why lead? Isn't it description? It is possible you can write it in the code i've posted above, just to make sure I'm doing everything right?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.