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:
- install kXML in your NetBeans J2ME project;
- use methods from org.kxml2.io.KXmlParser class;
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:
- know the XML document structure; in this example, the XML is the itcsolutions.eu RSS feed;
- know how the kXML methods: How to use kXML to parse XML files in J2ME projects;
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:
- create and initialize the KXmlParser using the InputStreamReader provided by the HttpConnection;
- 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;
- 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;
- for any other node than <item> skip it and its details using skipSubTree() method;
- 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:
You can download the full source code, including a sample test MIDlet.
Well i am trying to build this application but i am facing some problem . I am getting exception ¨Uncaught Exception java/lang/NoClassDefFoundError: org/kxml2/io/KXmlParser¨
i had used Kxml2 jar … I need help urgently.
Hi Ratnesh,
Have you added the kxml library to your J2ME project ? If yes, have you downloaded and tested the sample application from the post ?
If the sample application is working but not your project please show me the import statements and the statement that generates the error.
Hi, Please can you assist me in my project, i am building a J2ME application that has a news, forex and weatherapps in one midlet, i intend using your Rss feed example for the news area, i hav eused the VMD as the main form and i will want to link it to your sample midlet but in the sam eproject, how do i link them?
Thanks
Hi Andre,
It is simple to import the code sample into your project:
1. download and open the zip archive
2. copy the 2 files from the \eu\itcsolutions\rssparser\utility folder into your project directory
3. edit the 2 files and change the package name based on your own package structure (modify the package eu.itcsolutions.rssparser.utility; declaration)
4. as you already have a Midlet, create a new class that extends List and copy most of the XMLMidlet.java in the new class (code from startApp() can go in the class constructor)
If you still have problems, I can give you the class from step 4.
Hi, i make a j2me app, it runs very well but when i built with obfuscate, it cannot get data from internet.