Trying to parse XML in Android app with SAXParser - java

I'm new to Android development, and I'm using the New Boston tutorials to guide me through parsing some xml I have retrieved from an API, however it doesn't seem to be working for me I think the problem is somewhere in the handler, anywhere here is my code, I'll start with the relevent excerpt from the application class:
String test = null;
try {
//Assign XML to test string
test = new DownloadTextTask().execute(params).get();
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
XMLReader xr = sp.getXMLReader();
//create handler
HandlingXMLStuff doingWork = new HandlingXMLStuff();
xr.setContentHandler(doingWork);
//parse xml
xr.parse(test);
//Assign parsed xml to string
String information = "this is the access token: " + doingWork.getInformation();
//Output parsed XML
TextView myTextView = (TextView) findViewById(R.id.mytextview);
myTextView.setText(information);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Now here is the handler:
XMLDataCollected info = new XMLDataCollected();
boolean isUser = false;
boolean isToken = false;
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException{
if(localName.equals("user")){
isUser = true;
}else if(localName.equals("access_token")){
isToken = true;
}
}
public void characters (char ch[], int start, int length)
{
String str = null;
for (int i = start; i < start + length; i++) {
StringBuilder sb = new StringBuilder(str);
sb.append(ch[i]);
str = sb.toString();
}
if (isUser){
int u = Integer.parseInt(str);
info.setID(u);
}
else if(isToken){
info.setToken(str);
}
}
public String getInformation()
{
return info.dataToString();
}
XMLDataCollected Class:
public class XMLDataCollected {
int userId = 0;
String accessToken = null;
public void setID(int i){
userId = i;
}
public void setToken(String t){
accessToken = t;
}
public int getUserId(){
return userId;
}
public String dataToString(){
return accessToken;
}
And finally here is the XML that I am trying to parse:
<xml>
<user>1</user>
<access_token>a5923jh34gdhei592jdyeo3jk2354323ji4</access_token>
<status>Login Successful</status>
</xml>
Any help anyone can give me with this will be highly apreciated

I also followed that tutorial but I also didn't understand why it wasn't working.
I did some research and came with XmlPullParser, it is very easy to use and works really well. Here is the documentation for the XmlPullParser:
http://developer.android.com/reference/org/xmlpull/v1/XmlPullParser.html
Hope it helps!

Related

Storm bolt executes more than its parent

I have a Topology which contains a KafkaSpout and 2 bolts.
BoltParseJsonInput and its execute method:
public void execute(Tuple input) {
// TODO Auto-generated method stub
String data = input.getString(4);
js = new JSONObject(data);
String userId = js.getString("userId");
String timestamp = js.getString("timestamp");
counter++;
System.out.println(counter);
collector.emit(input, new Values(userId, timestamp));
collector.ack(input);
}
BoltInsertRedis and its execute method
public void execute(Tuple input) {
// TODO Auto-generated method stub
String userId = input.getStringByField("userId");
int timestamp = 0;
try {
timestamp = convertTimestampToEpoch(input.getStringByField("timestamp"));
} catch (ParseException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
String timestep = this.prefix + timestamp/10;
String curTimestamp = jedis.hget(timestep, userId);
if(curTimestamp == null || Integer.parseInt(curTimestamp) < timestamp) {
jedis.hset(timestep, userId, Integer.toString(timestamp));
}
collector.ack(input);
}
BoltInsertRedis get the input from BoltParseJsonInput
builder.setBolt("ParseJsonInput-Bolt", new BoltParseJsonInput()).shuffleGrouping("Kafka-Spout");
builder.setBolt("BoltRedisUserLastActive-Bolt", new BoltRedisUserLastActive()).shuffleGrouping("ParseJsonInput-Bolt");
But when I submit this topology into Storm, BoltInsertRedis execute more than BoltParseJsonInput
Can you explain to me what is the problem here?
I found that my ParseJsonBolt had made an exception at message 25700 and it keeps replaying execution at that point. When I made a try catch, it works well

Android Java retrieve JSON values and store as object in list

I would like to connect to Api link which can have multiple pages and store all the JSON values as a object in a list.
Here is a Api link example with multiple pages, note the number as last being the page you're on.
Problems that I have so far encountered and unable to solve. Return type of doInBackground as constructor class apiRootObject and how to deserialize the Json result, its logical why it doesnt work since I its extended from AsyncTask but i do not know how to work around this problem or what other road to take.
This is the code I have so far.
Calling the initial function in my Activity.java
String userSearchRequest = search_activity_data.getString("userSearchRequest");
String URL = "http://www.gw2spidy.com/api/v0.9/json/item-search/" + userSearchRequest + "/";
//Api link example with multiple pages = "http://www.gw2spidy.com/api/v0.9/json/item-search/Iron"
AsyncFetch parkingInfoFetch = new AsyncFetch(this);
parkingInfoFetch.setOnResponse(this);
parkingInfoFetch.execute(URL);
My AsyncFetch.java class which is called from aboves code
public class AsyncFetch extends AsyncTask {
public AsyncFetch(Context context) {
this.context = context;
}
private Context context;
private JSONObject jsonObject;
private onResponse onResponse;
public void setOnResponse(onResponse onResponse) {
this.onResponse = onResponse;
}
#Override
protected apiRootObject doInBackground(String... params) { //Incompatible return type
// TODO Auto-generated method stub
apiRootObject apiRootObject = null;
apiRootObject tempApiRootObject = null;
int page = 0;
try {
do {
HttpGet get = new HttpGet(params[0] + page);
HttpClient client = new DefaultHttpClient();
HttpResponse response = client.execute(get);
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity);
//jsonObject = new JSONObject(result);
tempApiRootObject = /*Deserialize into <RootObject>(result)*/
if (apiRootObject == null){
apiRootObject = tempApiRootObject;
}
else{
apiRootObject.results.addAll(tempApiRootObject.results);
apiRootObject.count += tempApiRootObject.count;
}
page++;
}
while(tempApiRootObject.last_page != tempApiRootObject.page);
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return apiRootObject;
}
#Override
protected void onPostExecute(JSONObject result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
this.onResponse.onResponse(result);
}
public interface onResponse {
public void onResponse(JSONObject object);
}
}
And back in the activity.java everything is being added to the list in the onResponse function.
public void onResponse(JSONObject object) {//Still expecting a JSONObject while I am changing this return type
Log.i("gw2Log", object.toString());
apiRootObject resultClass = new apiRootObject();
try {
resultClass.setCount(object.getInt("count"));
resultClass.setPage(object.getInt("page"));
resultClass.setLast_page(object.getInt("last_page"));
resultClass.setTotal(object.getInt("total"));
JSONArray list = new JSONArray(object.getString("results"));
for (int i = 0; i < resultClass.getCount(); i++) {
JSONObject resultsObject = list.getJSONObject(i);
apiResults temp = new apiResults();
temp.setData_id(resultsObject
.getInt("data_id"));
temp.setName(resultsObject
.getString("name"));
temp.setRarity(resultsObject
.getInt("rarity"));
temp.setRestriction_level(resultsObject
.getInt("restriction_level"));
temp.setImg(resultsObject
.getString("img"));
temp.setType_id(resultsObject
.getInt("type_id"));
temp.setSub_type_id(resultsObject
.getInt("sub_type_id"));
temp.setPrice_last_changed(resultsObject
.getString("price_last_changed"));
temp.setMax_offer_unit_price(resultsObject
.getInt("max_offer_unit_price"));
temp.setMin_sale_unit_price(resultsObject
.getInt("min_sale_unit_price"));
temp.setOffer_availability(resultsObject
.getInt("offer_availability"));
temp.setSale_availability(resultsObject
.getInt("sale_availability"));
temp.setSale_price_change_last_hour(resultsObject
.getInt("sale_price_change_last_hour"));
temp.setOffer_price_change_last_hour(resultsObject
.getInt("offer_price_change_last_hour"));
resultClass.addObject(temp);
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for(int i = 0; i < resultClass.count; i++) {
Log.i("gw2Log", resultClass.getObject(i).name);
}
}
Ofcourse there are also 2 constructor classes apiResults and apiRootObject.
EDIT:
If you take the link on the top of the question you get a lot of JSON values returned, every page can have 50 of these results if there are more a new page is created.
I want to connect to this Api link, and retrieve all values that are being returned. If there are multiple pages it needs to loop through all existing pages and add these JSON values to the exact same list.
I have asked a similiar question before in c# and here I've got it working but I now need the exact same in Android Java. For android java i was told i need to use AsyncTask in order to make a connection and do all of this in the background of the application. If there is a better or easier way, please enlighten me.
It might not be too late to use Retrofit .
gson is the easiest way to convert json into a class.
//your class
public class Foo {
public final int bar;
public final String bazz;
public foo(int bar, String bazz) {
this.bar = bar;
this.bazz = bazz;
}
}
//your json
{ "bar" : 4, "bazz" : "interesting content" }
//your gson call
Gson gson = new Gson();
Foo foo = gson.fromJson(json, Foo.class);
you can even do nested objects and it will deserialize them all.
public class FooHaver {
public final String prop1;
public final Foo foo;
}
//your json
{ "prop1" : "more content", "foo" : { "bar" : 4, "bazz" : "even more content" } }
you can also do json arrays as arrays or as a java List of any type you want
try this
#Override
protected apiRootObject doInBackground(String... params) { //Incompatible return type
// TODO Auto-generated method stub
apiRootObject apiRootObject = null;
apiRootObject tempApiRootObject = null;
List<apiRootObject> myList=new ArrayList<apiRootObject>();
int page = 0;
try {
do {
HttpGet get = new HttpGet(params[0] + page);
HttpClient client = new DefaultHttpClient();
HttpResponse response = client.execute(get);
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity);
jsonObject = new JSONObject(result);
//handling json exceptions
if(jsonObejct!=null && !jsonObject.isNull("page")&&..){
tempApiRootObject.page=jsonObject.getString("page");
tempApiRootObject.last_page=jsonObject.getString("last_page");
//here we put the results in the tempsApiRootObject
JSONArray ja = jsonObject.getJSONArray("results");
for (int i = 0; i < ja.length(); i++) {
JSONObject c = ja.getJSONObject(i);//this is an item
int data_id= c.getInt("data_id");
String name= c.getString("name");
//the other values
//here you add them in your arraylist of <apiResults> (*)
}
//and here we add the arraylist in (*) to tempApiRootObject
myList.add(tempApiRootObject);
/* if (apiRootObject == null){
apiRootObject = tempApiRootObject;
}
else{
apiRootObject.results.addAll(tempApiRootObject.results);
apiRootObject.count += tempApiRootObject.count;
}*/ i didn't understand this
}page++;
}
while(tempApiRootObject.last_page != tempApiRootObject.page);
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return myList// apiRootObject;
}
and this
public void onResponse(List<apiRootObject> myList) {
for(int i=0;i++;i<myList.size()){
apiRootObject resultClass =myList.get(i);
//do something
}
}

NoSuchMethodException loading Build.getRadioVersion() using reflection

I'm trying to load the radio version of the Android device using reflection. I need to do this because my SDK supports back to API 7, but Build.RADIO was added in API 8, and Build.getRadioVersion() was added in API 14.
// This line executes fine, but is deprecated in API 14
String radioVersion = Build.RADIO;
// This line executes fine, but is deprecated in API 14
String radioVersion = (String) Build.class.getField("RADIO").get(null);
// This line executes fine.
String radioVersion = Build.getRadioVersion();
// This line throws a MethodNotFoundException.
Method method = Build.class.getMethod("getRadioVersion", String.class);
// The rest of the attempt to call getRadioVersion().
String radioVersion = method.invoke(null).toString();
I'm probably doing something wrong here. Any ideas?
Try this:
try {
Method getRadioVersion = Build.class.getMethod("getRadioVersion");
if (getRadioVersion != null) {
try {
String version = (String) getRadioVersion.invoke(Build.class);
// Add your implementation here
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
Log.wtf(TAG, "getMethod returned null");
}
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
What Build.getRadioVersion() actually does is return the value of gsm.version.baseband system property. Check Build and TelephonyProperties sources:
static final String PROPERTY_BASEBAND_VERSION = "gsm.version.baseband";
public static String getRadioVersion() {
return SystemProperties.get(TelephonyProperties.PROPERTY_BASEBAND_VERSION, null);
}
According to AndroidXref this property is available even in API 4. Thus you may get it on any version of Android through SystemProperties using the reflection:
public static String getRadioVersion() {
return getSystemProperty("gsm.version.baseband");
}
// reflection helper methods
static String getSystemProperty(String propName) {
Class<?> clsSystemProperties = tryClassForName("android.os.SystemProperties");
Method mtdGet = tryGetMethod(clsSystemProperties, "get", String.class);
return tryInvoke(mtdGet, null, propName);
}
static Class<?> tryClassForName(String className) {
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
return null;
}
}
static Method tryGetMethod(Class<?> cls, String name, Class<?>... parameterTypes) {
try {
return cls.getDeclaredMethod(name, parameterTypes);
} catch (Exception e) {
return null;
}
}
static <T> T tryInvoke(Method m, Object object, Object... args) {
try {
return (T) m.invoke(object, args);
} catch (InvocationTargetException e) {
throw new RuntimeException(e.getTargetException());
} catch (Exception e) {
return null;
}
}

Checking if a message contains a string

I have have a class that check id a phrase is contained in a message, I tried to do it with Matcher and Pattern and with String.contains(), but the results returned are odd.
Here is the class:
public class MotsClesFilter implements EmailFilter {
final String NAME = "Filtrage par mots cles";
/*private Pattern chaineSpam;
private Matcher chaineCourriel;*/
private int nbOccMotSpam;
private byte confidenceLevel;
#Override
public String getFilterName() {
return this.NAME;
}
#Override
public byte checkSpam(MimeMessage message) {
analyze(message);
if(this.nbOccMotSpam==0)
this.confidenceLevel = 1;
else if (this.nbOccMotSpam>0 && this.nbOccMotSpam<2)
this.confidenceLevel = CANT_SAY;
else if (this.nbOccMotSpam>1 && this.nbOccMotSpam<3)
this.confidenceLevel = 50;
else if (this.nbOccMotSpam>3 && this.nbOccMotSpam<4)
this.confidenceLevel = 65;
else if (this.nbOccMotSpam>4 && this.nbOccMotSpam<5)
this.confidenceLevel = 85;
else this.confidenceLevel = 90;
return (getConfidenceLevel());
}
public void analyze(MimeMessage message){
try {
List<String> listeChaines = new ArrayList<String>();
BufferedReader bis = new BufferedReader(new InputStreamReader(new FileInputStream(new File("SpamWords.txt"))));
while(bis.ready()){
String ligne = bis.readLine();
listeChaines.add(ligne);
}
String mail = ((String.valueOf(message.getContent())));
//System.out.println(mail);
for (int j =0; j<listeChaines.size();j++){
//System.out.println(listeChaines.get(j));
Pattern chaineSpam = Pattern.compile(listeChaines.get(j),Pattern.CASE_INSENSITIVE);
Matcher chaineCourriel = chaineSpam.matcher(mail);
if (chaineCourriel.matches())
this.nbOccMotSpam++;
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (MessagingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public byte getConfidenceLevel() {
// TODO Auto-generated method stub
return this.confidenceLevel;
}
#Override
public boolean enabled() {
// TODO Auto-generated method stub
return true;
}
}
The results returned by checkSpam are always 1 if use matches and 90 if I use find, it also returns 90 when I use mail.contains(listeChaines.get(j)).
That means that the message doesn't match any of the strings in the file, but that there are at least 5 strings in the file that can be found inside the message.
matches() checks if the whole string matches the pattern. Not if some substring matches it.

Getting SVN Log of a particular Date Range in Java

I am trying to get the log from a SVN repo using SVNKit.
public static void svnLogTest() {
final SvnOperationFactory svnOperationFactory = new SvnOperationFactory();
final SvnLog log = svnOperationFactory.createLog();
SVNURL url = null;
try {
url = SVNURL
.parseURIEncoded("https://svn-repo");
} catch (SVNException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
log.setSingleTarget(SvnTarget.fromURL(url));
log.addRange(SvnRevisionRange.create(SVNRevision.create(111),
SVNRevision.create(222)));
log.getRevisionRanges();
SVNLogEntry logEntry = null;
try {
logEntry = log.run();
System.out.println(logEntry.getAuthor() + " " + logEntry.getRevision() + " "
+ logEntry.getDate());
} catch (SVNException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
But it will give me only the first revision, How should I iterate to print the log for a particular date range ?
This is because
log.run();
always returns only one log entry (the same is true for other SvnOperation#run methods). To get all entries use receiver:
log.setReceiver(new ISvnObjectReceiver<SVNLogEntry>() {
#Override
public void receive(SvnTarget target, SVNLogEntry logEntry) throws SVNException {
//process logEntry here
}
});
log.run();

Categories

Resources