Android + saxParser + storing objects into ArrayList - android

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.

Related

New to SAX Parser so need this BASIC

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;
}

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

featching cat_desc according cat_name from xml

I have to display cat_name in listview and when i click any name it will display it's cat_description. my url is http://mobileecommerce.site247365.com/admin/catdata.xml
I can able to display name in listview.My problem is i parse whole cat_desc but i want particular cat_desc according to cat_name.if any one have an idea for this?
I use
if(currenttag.equals("Cat_Desc"))
sitesList.setCat_Desc(String.valueOf(ch,start,length));
For set cat_desc. but it will set all cat_desc but i want specific cat_desc.
When i fetching cat_desc i use sitelist.getcatdesc().size().It will show me approximately 4500.
If any one having any solution or give me solution for this.
My Handler-
public void startElement(String uri, String localName, String qName,Attributes attributes) throws SAXException
{
currenttag=localName;
if(currenttag.equals("NewDataSet")) {
currentElement =true;
sitesList = new SitesList();
}
}
public void endElement(String uri, String localName, String qName)throws SAXException
{
super.endElement(uri, localName, qName);
if(qName.equals("NewDataSet"))
{
currentElement = false;
}
}
public void characters(char[] ch, int start, int length)throws SAXException
{
if(currenttag.equals("Cat_Name"))
sitesList.setCat_Name(String.valueOf(ch,start,length));
else if(currenttag.equals("Cat_Desc"))
sitesList.setCat_Desc(String.valueOf(ch,start,length));
java class--
for (int i = 0; i less than sitesList.getCat_Name().size(); i++)
catNames[i]=sitesList.getCat_Name().get(i);
for(int j=0; j less than sitesList.getCat_Desc().size();j++)
catdesc[j]=sitesList.getCat_Desc().get(j);
Thanks and Regards
Arpit
If I'm understanding you correctly, you can modify this code:
else if(currenttag.equals("Cat_Desc"))
sitesList.setCat_Desc(String.valueOf(ch,start,length));
To this
else if(currenttag.equals("Cat_Desc")){
sitesList.setCat_Desc(String.valueOf(ch,start,length));
if(currentCat.equals("desired_cat"){
specialDescription = String.valueOf(ch,start,length);
Where specialDescription is a field (instance variable) in your SaxParser class.

checking resources in xml and displaying icons for the resources in android

hai every one. i am new to android. in my project i had some problems reading xml files. In my xml i have included some audios and videos paths and i want to read the xml file through the code and i want to display some images n my view if there are some audio or video files. can any body tel how to read the xml file.
thanking you in advance
Ok first you need to create a parser Below is the code to do this:
public static void readTemplateFile(Context context) {
/**
Include File Checking
*/
try {
XML_Handler_Template myExHan = new XML_Handler_Template();
InputStreamReader isr = new
FileReader( new File(Environment.getExternalStorageDirectory().getPath() + "/Library Template.xml" ));
XML_Handler_Template.context = context;
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
XMLReader xr = sp.getXMLReader();
xr.setContentHandler((ContentHandler) myExHan);
xr.parse(new InputSource(isr));
} catch (Exception e) {
Toast.makeText(context, ">" + e.getMessage(), Toast.LENGTH_LONG).show();
}
}
You then need a Handler Class. In the above example my class is called XML_Handler_Template.
FileReader( new File(Environment.getExternalStorageDirectory().getPath() + "/FILEPATH/FILE.XML" ));
Here is the XML_Handler_Class at the moment it is blank:
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class XML_Handler_Template extends DefaultHandler{
public static Context context = null;
#Override
public void startDocument() throws SAXException {
//this is called when the document is first read
}
#Override
public void startElement(String namespaceURI, String localName,
String qName, Attributes atts) throws SAXException {
//This is called when a new Tag is opened
//localName holds the Tag Name, the Value is got from the
//Characters function at the end of this class
//the attributes for each tag are stored in the atts array, you can either handle the attribute values here or pass the information to a separate function to handle them,
if (atts.getLength()>0){
for (int i=0;i<atts.getLength();i++){
addAttrib(atts.getLocalName(i) , atts.getValue(i)) ;
}
}
}
#Override
public void endElement(String namespaceURI, String localName, String qName)
throws SAXException {
//This is called when a Tag is closed
}
#Override
public void endDocument() throws SAXException {
//this is called when the document is closed
}
#Override
public void characters(char ch[], int start, int length) {
//This is where the value of a Tag are read
String value = new String( ch , start , length );
// You may want to include a replaceAll("\r","") and replaceAll("\n","") to remove any hidden chars
}
}
have a play with this and see how you get on for now =0) I passed a context to the class so whilst i was learning I could use toasts to show me the values that were being read.

Android SAX parser not getting full text from between tags

I've created my own DefaultHandler to parse rss feeds and for most feeds it's working fine, however, for ESPN, it is cutting off part of the article url due to the way ESPN formats it's urls. An example of a full article url from ESPN..
http://sports.espn.go.com/nba/news/story?id=5189101&campaign=rss&source=ESPNHeadlines
The problem is for some reason the DefaultHandler characters method is only getting this from the tag that contains the above url.
http://sports.espn.go.com/nba/news/story?id=5189101
As you can see, it's cutting everything off the url from the ampersand escape code and after. How can I get the SAX parser to not cut my string off at this escape code? For ref. here is my characters method..
public void characters(char ch[], int start, int length) {
String chars = (new String(ch).substring(start, start + length));
try {
// If not in item, then title/link refers to feed
if (!inItem) {
if (inTitle)
currentFeed.title = chars;
} else {
if (inLink)
currentArticle.url = new URL(chars);
if (inTitle)
currentArticle.title = chars;
if (inDescription)
currentArticle.description = chars;
if (inPubDate)
currentArticle.pubDate = chars;
if (inEnclosure) {
}
}
} catch (MalformedURLException e) {
Log.e("RSSReader", e.toString());
}
}
Rob W.
As you can see, it's cutting
everything off the url from the
ampersand escape code and after.
From the documentation of the characters() method:
The Parser will call this method to
report each chunk of character data.
SAX parsers may return all contiguous
character data in a single chunk, or
they may split it into several chunks;
however, all of the characters in any
single event must come from the same
external entity so that the Locator
provides useful information.
When I write SAX parsers, I use a StringBuilder to append everything passed to characters():
public void characters (char ch[], int start, int length) {
if (buf!=null) {
for (int i=start; i<start+length; i++) {
buf.append(ch[i]);
}
}
}
Then in endElement(), I take the contents of the StringBuilder and do something with it. That way, if the parser calls characters() several times, I don't miss anything.
#Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
// TODO Auto-generated method stub
sb=new StringBuilder();
if(localName.equals("icon"))
{
iconflag=true;
}
}
#Override
public void characters (char ch[], int start, int length) {
if (sb!=null && iconflag == true) {
for (int i=start; i<start+length; i++) {
sb.append(ch[i]);
}
}
}
#Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
// TODO Auto-generated method stub
if(iconflag)
{
info.setIcon(sb.toString().trim());
iconflag=false;
}
}
So I figured it out, the code above is the solution.
I ran into this problem the other day, it turns out the reason for this is the CHaracters method is being called multiple times in case any of these Characters are contained in the Value:
" "
' &apos;
< <
> >
& &
Also be careful about Linebreaks / newlines within the value!!!
If the xml is linewrapped without your controll the characters method wil also be called for each line that is in the statement, plus it will return the linebreak! (which you manually need to strip out in turn).
A sample Handler taking care of all these problems is this one:
DefaultHandler handler = new DefaultHandler() {
private boolean isInANameTag = false;
private String localname;
private StringBuilder elementContent;
#Override
public void startElement(String uri, String localName,String qName, Attributes attributes) throws SAXException {
if (qname.equalsIgnoreCase("myfield")) {
isInMyTag = true;
this.localname = localname;
this.elementContent = new StringBuilder();
}
}
public void characters(char[] buffer, int start, int length) {
if (isInMyTag) {
String content = new String(ch, start, length);
if (StringUtils.equals(content.substring(0, 1), "\n")) {
// remove leading newline
elementContent.append(content.substring(1));
} else {
elementContent.append(content);
}
}
}
public void endElement(String uri, String localName, String qName) throws SAXException {
if (qname.equalsIgnoreCase("myfield")) {
isInMyTag = false;
// do something with elementContent.toString());
System.out.println(elementContent.toString());
this.localname = "";
}
}
}
I hope this helps.

Categories

Resources