How to parse XML, RSS feed with kXML in a J2ME MIDlet

More an more mobile devices are used to access Internet and connected services. One efficient way to transfer data between different platforms and technologies is to use XML files, which are simple text files formatted accordingly to the XML rules.

IN order to process an XML file and to extract needed data you need a XML parser which is a text process engine.

The problem for J2ME MIDlets is that there are mobile devices that don’t support the XML API for Java ME additional package (JSR 280). In order to solve this problem, we need an independent and lightweight XML parser that must be fast and with a small impact on the memory. Two possible solutions are kXML and NanoXML.

In the next MIDlet example (You can download the full source code, including a sample test MIDlet), we will use kXML to parse a RSS feed, the itcsolutions.eu RSS feed.

How to use kXML

In order to understand how to:

check How to use kXML to parse XML files in J2ME projects post.

How to access a Web based XML document from a MIDlet

In order to access a XML document on the Web, we need a HttpConnection object. Once we get an active connection, we can process the XML at byte or char level.

For processing the remote XML at char level, we need an InputStreamReader (it will be created based on the InputStream object). This will be the input for the kXML parser.

Because operations that require network access can block the main thread, the entire procedure of getting the XML file from the given URL and parsing it, will be executed in a secondary thread. This will prevent the application to block and it will allow users to use the application commands like Exit. Other wise, the main thread will wait for the network operation to end in order to execute command handlers.

The method that handles the HTTP connection is getXMLFeed():

public void getXMLFeed(final String url) {
    Thread t = new Thread() {
        public void run() {
            HttpConnection myConnection = null;
            try {
                //open the connection
                myConnection = (HttpConnection) Connector.open(url);
		//get the bytes stream
                InputStream stream = myConnection.openInputStream();
		//call the parsing method
                ParseXMLFeed(stream);
            } catch (Exception error) {
                parentMidlet.DisplayError(error);
            } finally {
                //close the connection
                try {
                    if (myConnection != null) {
                        myConnection.close();
                    }
                } catch (IOException eroareInchidere) {
		//calls a method from the MIDlet that display an alert
                    parentMidlet.DisplayError(eroareInchidere);
                }
            }
        }
    };
    //starts the thread
    t.start();
}

How to parse the RSS feed using the kXML parser

In order to use the kXML parser you must:

The method that implements the XML parsing is ParseXMLFeed():

  • the method argument is an InputStream reference; this will be used to create a Reader reference needed to process the XML at char level and also needed to define the input for the kXmlParser.
  • the method extracts only the title and the link for each RSS item; the data is stored in a News (class defined in the utility package) item; the News item is added in a Vector defined at MIDlet level using the midlet addNews() method;

The steps that define the process of parsing the XML feed are:

  1. create and initialize the KXmlParser using the InputStreamReader provided by the HttpConnection;
  2. because the <item> nodes are sub-nodes of <channel> and we want to process them in a iterative way, we must go past <rss> into <channel> sub-nodes collection;
  3. loop through the nodes using nextTag() method and for each <item> start tag, get the title and the link; the title and the link are used to create a News object that is added to the Vector collection of the Midlet;
  4. for any other node than <item> skip it and its details using skipSubTree() method;
  5. when we reach a <channel> node, it means we have finished its sub-tree because this is the end tag;
private void ParseXMLFeed(InputStream input)
        throws IOException, XmlPullParserException {
    Reader dataReader = new InputStreamReader(input);

    //kXML parser
    KXmlParser myParser = new KXmlParser();
    myParser.setInput(dataReader);

    //skip the first node - rss
    myParser.nextTag();
    myParser.require(XmlPullParser.START_TAG, null, "rss");
    //skip the second node - channel
    myParser.nextTag();
    myParser.require(XmlPullParser.START_TAG, null, "channel");
    myParser.nextTag();
    myParser.require(XmlPullParser.START_TAG, null, "title");

    while (myParser.getEventType() != XmlPullParser.END_DOCUMENT) {
        String name = myParser.getName();
        //this is for reaching the end tag for channel node
        if (name.equals("channel")) {
            break;
        }
        //this is for each item node in the RSS feed
        if (name.equals("item")) {
            //process it only if it is reached the start tag
            if (myParser.getEventType() != XmlPullParser.END_TAG) {
                myParser.nextTag();
                String title = myParser.nextText();
                myParser.nextTag();
                String link = myParser.nextText();

                //create a new News item
                News news = new News(title, link);
                parentMidlet.addNews(news);
            }
        } else {
            //if it is not the item node the skip it and all its details
            myParser.skipSubTree();
        }
        //move to the next tag
        myParser.nextTag();
    }
    //close the input stream - job done
    input.close();
}

How is working the mobile application

  • the application is managing the RSS feed items (only the title and the link) using a Vector collection of News objects, news;
  • the title of each News object is displayed in a List type form, myNewsList;
  • in order to add elements to the Vector collections, the MIDlet provide a public method addNews(); the method also set the List form, myNewsList, as the current one;
//method called by the parsing thread
public void addNews(News newsItem){
    news.addElement(newsItem);
    myNewsList.append(newsItem.getTitle(),null);
    myDysplay.setCurrent(myNewsList);
}
  • the application has 2 commands: one for closing the application, cmdExit, and one, cmdDetails, for displaying in a Alert details (the link) of the selected title;
public void commandAction(Command command, Displayable displayable) {
    if(command == cmdExit){
        destroyApp(false);
        notifyDestroyed();
    } else
        if(command == cmdDetails || command == List.SELECT_COMMAND){
        //get the index of the selected title
        int index = myNewsList.getSelectedIndex();
        if(index!=-1) {
            //get the Vector element at that index - News object
            News newsItem = (News)news.elementAt(index);

            //display the link in an Alert
            Alert message = new Alert(newsItem.getTitle(),
                    newsItem.getLink(),
                    null,
                    null);
            message.setTimeout(Alert.FOREVER);
            myDysplay.setCurrent(message,myNewsList);

        } else
            return;
        }
}

the MIDlet has 2 threads; the main one which is used to display the List form and to manage the 2 commands; the second thread implements the parsing process; the second thread starts when the getXMLFeed() method is called;

    public void startApp() {
        myNewsList.setCommandListener(this);

        //the XML file url
        String url = "http://www.itcsolutions.eu/feed/";

        ParseThread myThread = new ParseThread(this);
        //this will start the second thread
        myThread.getXMLFeed(url);

        Display.getDisplay(this).setCurrent(myNewsList);
    }

The main screens of the MIDlet are:

RSS titles list

RSS titles list

RSS title details

RSS title details

You can download the full source code, including a sample test MIDlet.