Search This Blog

Wednesday, December 2, 2009

Pull Parser

Although our last application is working pretty good with SAX Parser, but as i said i'm gonna use Pull Parser instead, to see how it works, as far as i know Pull Parsing is a bit slower that SAX parsing but it gives the ability to stop parsing in the middle of a document and this means that Pull Parsing would be well suited in a situation in which we just need some portions of XML and not the whole of it.
In our application we need the whole xml but i think now that we are dealing with XML parsing it would be a good opportunity to dig into PullParser method and draw a comparison between these two XML parsing methods.(you can also use DOM parsing, but i reckon it's safe to say that you shouldn't ever use it unless you really have to).
Here is our Pull Parser class:



package com.news.search;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.xmlpull.v1.XmlPullParser;
import android.util.Xml;

import com.yahoo.search.ImageThumbnail;
import com.yahoo.search.NewsSearchResult;
import com.yahoo.search.xmlparser.XmlParserImageThumbnail;
import com.yahoo.xml.XmlParser;


public class NewsPullParser {

private InputStream input;

public final static String TITLE = "Title";
public final static String SUMMARY = "Summary";
public final static String URL = "Url";
public final static String CLICK_URL = "ClickUrl";
public final static String SOURCE = "NewsSource";
public final static String SOURCE_URL = "NewsSourceUrl";
public final static String LANGUAGE = "Language";
public final static String PUBLISH_DATE = "PublishDate";
public final static String MOD_DATE = "ModificationDate";
public static ArrayList newsTags;
static{
newsTags = new ArrayList();
newsTags.add(TITLE);
newsTags.add(SUMMARY);
newsTags.add(URL);
newsTags.add(CLICK_URL);
newsTags.add(SOURCE);
newsTags.add(SOURCE_URL);
newsTags.add(LANGUAGE);
newsTags.add(PUBLISH_DATE);
newsTags.add(MOD_DATE);
}



public NewsPullParser(InputStream stream){
this.input = stream;
}

public NewsSearchResult[] parse(List TagFilter) throws Exception{

ArrayList content = null;
XmlPullParser parser = Xml.newPullParser();

try{

parser.setInput(this.input,"UTF-8");
HashMap map = null;
int event = parser.getEventType();

while (event != XmlPullParser.END_DOCUMENT){
String name = null;

switch (event){

case XmlPullParser.START_DOCUMENT: content = new ArrayList();
break;
case XmlPullParser.START_TAG:
name = parser.getName();
if (name.equalsIgnoreCase("Result")){
map = new HashMap();
}else if(map != null && newsTags.contains(name) && TagFilter.contains(name)){

map.put(name,parser.nextText());

}
break;

case XmlPullParser.END_TAG:
name = parser.getName();
if (name.equalsIgnoreCase("RESULT") && map != null)
content.add(new PullParserNewsSearchResult(map));

break;
}

event = parser.next();
}


}catch(Exception exp){
throw exp;
}

return content.toArray(new NewsSearchResult[content.size()]);
}


private class PullParserNewsSearchResult implements NewsSearchResult {
private Map result;


public PullParserNewsSearchResult(Map result) {
this.result = result;
}

public String getTitle() {
return (String)result.get(TITLE);
}

public String getSummary() {
return (String)result.get(SUMMARY);
}

public String getUrl() {
return (String)result.get(URL);
}

public String getClickUrl() {
return (String)result.get(CLICK_URL);
}

public String getNewsSource() {
return (String)result.get(SOURCE);
}

public String getNewsSourceUrl() {
return (String)result.get(SOURCE_URL);
}

public String getLanguage() {
return (String)result.get(LANGUAGE);
}

public String getPublishDate() {
return (String)result.get(PUBLISH_DATE);
}

public String getModificationDate() {
return (String)result.get(MOD_DATE);
}

public ImageThumbnail getThumbnail() {
return null;
}
}


}




I added some kind of filtering to our parsing process because I though it was so silly to extract all those values and store them in memory without even using them.so let's just store those information that is required and
simply just skip those ones we are not interested in.

Our FecherThread's run() method will also gotta be changed :



public void run(){

request.getParameters().put("appid", "javasdktest");
// request.setResults(15);


do {
while(!this.anyRequest){

try{
synchronized (this) {
this.wait();
}
}catch(InterruptedException exp){
////Just Nothing
}

}

try{

NewsPullParser parser = new NewsPullParser(RestClient.call(request.getRequestUrl(), request.getParameters()));
ArrayList filter = new ArrayList();
filter.add(NewsPullParser.TITLE);
filter.add(NewsPullParser.SUMMARY);

Bundle content = new Bundle();
content.putSerializable("result",parser.parse(filter));
Message msg = new Message();
msg.setData(content);
this.callback.sendMessage(msg);


}catch(Exception exp){
exp.printStackTrace();

}


this.anyRequest = false;
this.lastRequest_finished = true;

}while(!this.stopFlag);

}




we can also get rid of executeAndParse() method since we no longer need it.
Done,that's it.... easy, wasn't it? now we are familiar with both SAX Parsing
and Pull Parsing in Android.

No comments: