New to SAX Parser so need this BASIC - android

if we do this in SAX Parser:
public class SAXXMLHandler extends DefaultHandler {
private List<Employee> employees;
private String tempVal;
private Employee tempEmp;
public SAXXMLHandler() {
employees = new ArrayList<Employee>();
}
public List<Employee> getEmployees() {
return employees;
}
// Event Handlers
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
// reset
tempVal = "";
if (qName.equalsIgnoreCase("employee")) {
// create a new instance of employee
tempEmp = new Employee();
}
}
public void characters(char[] ch, int start, int length)
throws SAXException {
tempVal = new String(ch, start, length);
}
public void endElement(String uri, String localName, String qName)
throws SAXException {
if (qName.equalsIgnoreCase("employee")) {
// add it to the list
employees.add(tempEmp);
} else if (qName.equalsIgnoreCase("id")) {
tempEmp.setId(Integer.parseInt(tempVal));
} else if (qName.equalsIgnoreCase("name")) {
tempEmp.setName(tempVal);
} else if (qName.equalsIgnoreCase("department")) {
tempEmp.setDepartment(tempVal);
} else if (qName.equalsIgnoreCase("type")) {
tempEmp.setType(tempVal);
} else if (qName.equalsIgnoreCase("email")) {
tempEmp.setEmail(tempVal);
}
}
}
for this :
<employee>
<id>2163</id>
<name>Kumar</name>
<department>Development</department>
<type>Permanent</type>
<email>kumar#tot.com</email>
</employee>
What we will do in SAX Parser for this :
<MyResource>
<Item>First</Item>
<Item>Second</Item>
</MyResource>
I am a newbie to SAX Parser.
Previously i had problems with DOM and PullParser for the same XML.
Isn't there any parser built for parsing this simple XML.

To parse an entry named MyResource that contains multiple entry of Item you can do something like that :
At first, initialize your variables inside the startDocument method to allow the reuse of your Handler :
private List<MyResource> resources;
private MyResource currentResource;
private StringBuilder stringBuilder;
public void startDocument() throws SAXException {
map = null;
employees = new ArrayList<Employee>();
stringBuilder = new StringBuilder();
}
Detect inside of startElement when a MyResource is starting. The tag name will usually be stored inside the qName argument.
When a MyResource is starting, you may want to create an instance of MyResource as a temporary variable. You will feed it until its end tag is reached.
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if ("MyResource".equals(qName)) {
currentResource = new MyResource();
}
stringBuilder.setLength(0); // Reset the string builder
}
The characters method is required to read the content of each tag.
Use StringBuilder to read characters. SAX may call more than once the characters method for each tag :
public void characters(char[] ch, int start, int length) throws SAXException {
stringBuilder.append(ch, start, length);
}
Inside the endElement, create a new Item each time the closed tag is named item AND a MyResource is being created (i.e. you have an instance of MyResource somewhere).
When the closed tag is MyResource, add it to a list of results and clean the temporary variable.
public void endElement(String uri, String localName, String qName) throws SAXException {
if("MyResource".equals(qName)) {
resources.add(currentResource);
currentResource = null;
} else if(currentResource != null && "Item".equals(qName)) {
currentResource.addItem(new Item(stringBuilder.toString()));
}
}
I am assuming that you have a List of Item inside MyResource.
Don't forget to add a method to retrieve the resources after the parse :
List<MyResources> getResources() {
return resources;
}

Related

How to parse xml having multiple child and in that child there is data?

Here is my xml,
<root>
<child>
<Lunchmenu>
<id>2</id>
<lunch_date>2013-10-24</lunch_date>
<break_name>Lunch</break_name>
<class_id/>
<school_id>1</school_id>
<batch_id/>
</Lunchmenu>
<Eatable>
<id>2</id>
<eatable_name>Apples</eatable_name>
</Eatable>
</child>
<child>
<Lunchmenu>
<id>2</id>
<lunch_date>2013-10-24</lunch_date>
<break_name>Lunch</break_name>
<class_id/>
<school_id>1</school_id>
<batch_id/>
</Lunchmenu>
<Eatable>
<id>3</id>
<eatable_name>Orange</eatable_name>
</Eatable>
</child>
I need to know that, is there any way to parse above xml's child as there are again two separate tags like Lunchmenu and eatable.
I am using sax parser to parse this xml.
I know how to parse single child tag having data and again its iteration, but here I am confused how to do it?
please suggest any solution if anyone knows How to parse it??
thank you
and my parser class is :
SchoolParser.java
public class SchoolParser extends DefaultHandler {
private List<School> schoolListData ;
private boolean isSuccess;
private School school;
StringBuilder tempData;
#Override
public void startDocument() throws SAXException {
super.startDocument();
Log.e("StudentListParser","startDocument");
schoolListData = new ArrayList<School>();
}
public List<School> getSchoolListData(){
return schoolListData;
}
#Override
public void startElement(String uri, String localName, String qName,
org.xml.sax.Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
if (localName.equals("School")) {
school = new School();
Log.e("SchoolParser", "-----START----");
}
tempData = new StringBuilder();
}
#Override
public void characters(char[] ch, int start, int length)
throws SAXException {
super.characters(ch, start, length);
tempData.append(new String(ch, start, length));
}
#Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
super.endElement(uri, localName, qName);
if(localName.equals("School")){
schoolListData.add(school);
Log.d("localName",localName);
}
else if (localName.equals("id")) {
Log.e("id", localName);
school.id = Integer.parseInt(tempData.toString());
} else if (localName.equals("school_name")) {
school.schoolName = tempData.toString();
Log.e("name", localName);
} else if (localName.equals("logo")) {
school.logo = tempData.toString().getBytes();
Log.e("logo", localName);
}else if (localName.equals("phone")) {
school.phn_no = tempData.toString();
Log.e("phn no", localName);
}
else if (localName.equals("School")) {
Log.e("SchoolParser", "----END---");
}
// int size = buffer.length();
// buffer.delete(0, size);
// Log.i("buffer is empty", ""+buffer.toString());
}
#Override
public void endDocument() throws SAXException {
super.endDocument();
isSuccess = false;
Log.e("StudentListParser", "endDocument");
}
}
May be you can use serialize logic to parse xml to direct java class object.
You can use below class..
package com.lib.android.util;
import java.io.InputStream;
import org.apache.log4j.Logger;
import org.simpleframework.xml.Serializer;
import org.simpleframework.xml.core.Persister;
import com.lib.android.util.logger.PLogger;
public class XmlParser
{
private static Logger log = new PLogger(XmlParser.class).getLogger();
public static Object Parse(Class<? extends Object> parseInto, InputStream is)
{
Serializer serializer = new Persister();
try
{
Object obj = serializer.read(parseInto, is);
return obj;
} catch (Exception e)
{
log.error(e.getMessage());
}
return null;
}
}
Hope it will help you..

Android SAXParser Leftovers

I have an Android app that parses XML using SAXParser. Everything goes ok, excepting some texts that get duplicated and trimmed. For example: "Just do it, even if you do not know how!" becomes " not know how!"
This is the DefaultHandler code. 10x!
DefaultHandler handler = new DefaultHandler()
{
Praise praise;
String elementValue = null;
Boolean elementOn = false;
#Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException
{
if (localName.equals("praise"))
{
praise = new Praise();
elementOn = true;
}
}
#Override
public void endElement(String uri, String localName, String qName) throws SAXException
{
// elementOn = false;
if (localName.equals("PRAISE_TEXT"))
{
praise.setPraiseText(elementValue);
}
if (localName.equals("MOOD"))
{
praise.setMood(elementValue);
}
if (localName.equals("RATING"))
{
praise.setRating(Integer.valueOf(elementValue));
}
if (localName.equals("praise"))
{
elementOn = false;
if (update)
{
if (database.getPraiseByText(praise.getPraiseText(), db) == null)
{
database.addPraise(db, praise.getPraiseText(), praise.getMood(),
Integer.valueOf(praise.getRating()));
}
}
else
database.addPraise(db, praise.getPraiseText(), praise.getMood(),
Integer.valueOf(praise.getRating()));
}
}
#Override
public void characters(char[] ch, int start, int length) throws SAXException
{
// StringBuffer b = new StringBuffer();
if (elementOn)
{
elementValue = new String(ch, start, length);}}};
In SaxParsing, you do not have guarantee that characters will be called only once!
For this, you should concatenate all the characters you receive withing the same element
This is a just your code with a small modification. You should use StringBuilder instead of using String (:
DefaultHandler handler = new DefaultHandler()
{
Praise praise;
String elementValue = null;
Boolean elementOn = false;
#Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException
{
elementValue = new String();
if (localName.equals("praise"))
{
praise = new Praise();
elementOn = true;
}
}
#Override
public void endElement(String uri, String localName, String qName) throws SAXException
{
if (localName.equals("PRAISE_TEXT"))
{
praise.setPraiseText(elementValue);
}
if (localName.equals("MOOD"))
{
praise.setMood(elementValue);
}
if (localName.equals("RATING"))
{
praise.setRating(Integer.valueOf(elementValue));
}
if (localName.equals("praise"))
{
elementOn = false;
if (update)
{
if (database.getPraiseByText(praise.getPraiseText(), db) == null)
{
database.addPraise(db, praise.getPraiseText(), praise.getMood(),
Integer.valueOf(praise.getRating()));
}
}
else
database.addPraise(db, praise.getPraiseText(), praise.getMood(),
Integer.valueOf(praise.getRating()));
}
}
#Override
public void characters(char[] ch, int start, int length) throws SAXException
{
// StringBuffer b = new StringBuffer();
if (elementOn)
{
elementValue = elementValue + new String(ch, start, length);
}
}
};
This problem often comes in SaxParsing. The Actual problem is it breaks the String by "/n" & only last part of String is available for us.
Now come to the solution, Take different booleans for tags(containing problems or for all).
In startElement method make relevent boolean true.
if (localName.equals("PRAISE_TEXT"))
{
isPrase= true'
praise.setPraiseText(elementValue);
}
in endElemet method make relevent boolean false.
if (localName.equals("PRAISE_TEXT"))
{
isPrase= false;
praise.setPraiseText(elementValue);
}
in characters method check for boolean like this:
if(isPrase)
{
elementValue = new String(ch, start, length);}}};
}

Android - using parsed xml data to update SQLite

just a reminder that I'm a noob so maybe my question is fairly stupid...
Anyway I'm using SAX to parse an XML file and I can correctly loop through the items and print their contents to the log. What I'd need though is for this parser to return a multidimensional associative array that I can iterate through and subsequently use to update an SQLite database...
Question(s):
Does such a thing exist in Android? Should I be using some other datatype instead? How is it done?
I'll include some code of the parser (the endElement method does the printing to log, so far it has one element per item but that will change, hence the need for multidimensional):
private boolean in_image = false;
private boolean in_homeimage = false;
StringBuilder sb;
#Override
public void characters(char[] ch, int start, int length)
throws SAXException {
for (int i=start; i<start+length; i++) {
sb.append(ch[i]);
}
//super.characters(ch, start, length);
}
#Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
if( localName.equals("image") && this.in_homeimage ){
this.in_homeimage = false;
Log.i("Extra", "Found homeimage: " + sb);
}
else if( localName.equals("image") ){
this.in_image = false;
Log.i("Extra", "Found image: " + sb);
}
//super.endElement(uri, localName, qName);
}
#Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
sb = new StringBuilder();
if( localName.equals("image") && attributes.getValue("name") == "home" )
this.in_homeimage = true;
else if( localName.equals("image") )
this.in_image = true;
//super.startElement(uri, localName, qName, attributes);
}
Thanks in advance

Android: How to parse same tags in SAX Parser?

I am trying to parse and get values from web service. The problem is that Web service has same element name tags which are creating problem to parse as I want to get their value but they are of same name So is difficult for me to mention them as localname.
<countryBean>
<id>236</id>
<name>United State</name>
</countryBean>
<secutiryQuestion1>
<id>2</id>
<question>What was your dream job as a child?</question>
</secutiryQuestion1>
<secutiryQuestion2>
<id>4</id>
<question>What is the name, breed, and color of your pet?</question>
</secutiryQuestion2>
<stateBean>
<country>236</country>
<id>5</id>
<name>California</name>
</stateBean>
<statusBean>
<id>1</id>
<name>Active</name>
</statusBean>
I want to get value of ID tag and other adjacent tag like name,question in different variables. and Here are 5 Id tags.
My class code is like
public class XmlParser extends DefaultHandler {
public RestfullResponse tempResponse = null;
String currentValue = null;
int ServiceType =0;
#Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
if(localName.equalsIgnoreCase("countryBean")){
tempResponse=new RestfullResponse();
}
}
/* (non-Javadoc)
* #see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
*/
#Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
if(ServiceType == 1)
{
if(localName.equalsIgnoreCase("id")){
tempResponse.setCountryId(currentValue);
}
if(localName.equalsIgnoreCase("name")){
tempResponse.setCountryName(currentValue);
}
if(localName.equalsIgnoreCase("id")){
tempResponse.setStateId(currentValue);
}
if(localName.equalsIgnoreCase("question")){
tempResponse.setstateBean(currentValue);
}
if(localName.equalsIgnoreCase("Id")){
tempResponse.setStatusId(currentValue);
}
if(localName.equalsIgnoreCase("requestSuccess")){
tempResponse.setStatus(currentValue);
}
}
}
#Override
public void characters(char[] ch, int start, int length)
throws SAXException {
currentValue = new String(ch, start, length);
}
public RestfullResponse getResponse(){
return tempResponse;
}
}
please Help to store them in
String CountryName= "";
String CountryId = "";
String Statename = "";
String StateId ="";
String Status = "";
String StatusId = "";
String Username ="";
String SecurityQuestion = "";
String SecurityQuestionId = "";
Add boolean variable isCountryBean;
boolean isCountryBean = false , isSecurityQuestion1 = false;
And in startElement(....) write:
if(localName.equalsIgnoreCase("countryBean")){
isCountryBean = true;
// other stuff
} else if (localName.equalsIgnoreCase("secutiryQuestion1")){
isSecurityQuestion1 = true;
isCountryBean = false;
}
And in endElement(...) check:
if(localName.equalsIgnoreCase("id")){
if(isCountryBean){
tempResponse.setCountryId(currentValue);
}
}
if(localName.equalsIgnoreCase("name")){
if(isCountryBean){
isCountryBean = false;
tempResponse.setCountryName(currentValue);
}
}
Do it for other most outward tags. Hope it will help you.
You need to maintain the stack of root nodes.
Take a variable of type String root and maintain a stack of root element.
Inside startElement method:
public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException,
IllegalArgumentException
{
// call to abstract method
onStartElement(namespaceURI, localName, qName, atts);
// Keep the trace of the root nodes
if (root.length() > 0)
{
root= root.concat(",");
}
root= root.concat(localName);
}
Inside endElement method:
public void endElement(String namespaceURI, String localName, String qName) throws SAXException
{
// remove the end element from stack of root elements
int index = root.lastIndexOf(',');
if (index > 0)
{
root= root.substring(0, index);
}
onEndElement(namespaceURI, localName, qName);
}

Android + saxParser + storing objects into ArrayList

I'm using a simple implementation of saxParser. Within my endElement method, I'm storing vo objects to an ArrayList. Unfortunately when I loop over my List, it only returns the last item from my xml data. Just wondering what I'm doing wrong? Relavent code below:
public class MyXMLHandler extends DefaultHandler {
private StringBuffer buffer = new StringBuffer();
private Boolean currentElement = false;
private StoreDetails storeDetails = new StoreDetails(); //vo object
private ArrayList<StoreDetails> dataList = new ArrayList<StoreDetails>(); //list of vo
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
currentElement = true;
}
#Override
public void endElement(String uri, String localName, String qName) throws SAXException {
currentElement = false;
if (localName.equals("StoreID")) {
buffer.toString().trim();
storeDetails.setStoreId(buffer.toString());
} else if (localName.equals("StoreName")) {
buffer.toString().trim();
storeDetails.setStoreName(buffer.toString());
} else if (localName.equals("StoreCategory")) {
buffer.toString().trim();
storeDetails.setStoreCategory(buffer.toString());
//add vo object to ArrayList - dataList
dataList.add(storeDetails);
}
buffer = new StringBuffer();
}
#Override
public void characters(char[] ch, int start, int length) throws SAXException {
if (currentElement) {
buffer.append(ch, start, length);
currentElement = false;
}
}
#Override
public void endDocument() throws SAXException {
Log.i("TAG", "DONE PARSING XML");
for(StoreDetails details : dataList){
//ISSUE - returning only the last row in my xml data (over and over)
Log.i("TAG", "Details ID: " + details.getStoreId());
}
}
}
You have to reinitialize the object after adding it to array list. Otherwise it saves the last data.
Now, For example , If your xml is something like this , then
<Item>
<StoreID></StoreID>
<StoreName></StoreName>
<StoreCategory></StoreCategory>
</Item>
At startElement you have to initialize the 'storeDetails' object.
storeDetails = new StoreDetails();
At endElement you have to add the 'storeDetails' object to the array list.
dataList.add(storeDetails);
In this way , when will occur at startElement , 'storeDetails' object will get initialize , it will save current item's information( StoreID,StoreName,StoreCategory ) & then when will occur at endElement , 'storeDetails' object will be added to the arraylist. Thus the parsing will go on and you will get all the data in your arraylist.
I guess the problem is that you use single instance of "vo object" for all items in ArrayList. You need smth like this in startElement:
storeDetailes = new ...
Refer to documents, explaning Java memory model.

Categories

Resources