Aug 2, 2011

Android Plist Parser



The Android-PList-Parser is designed to work with valid PList XMLs only. Before you start getting into the code, you want to be certain that the PList XML you're working with is valid according to the DTD). If it's valid, proceed to the next paragraph. you may want to write code from scratch instead of trying to modify this code (since it's algorithm relies on the assumption of validity).

The basic rule for the algorithm is that elements are treated in two different ways: ones that can have children (Dict and Array), and ones that can't. Elements that can have children are pushed onto a ArrayList method is used. With these concepts in mind, reading the code should be a little easier.

This is very basic parser. you require to modify as per your requirement.

Let's me show you the example which I have prepare specially for my Plist problem. There are two main file 1. DataModel.java and 2. ParsePlist.java

1. DataMode.java - A model class holds the value of Plist.
2. ParsePlist.java - Class which parse the plist.
3. Sample.plist  - Plist file placed in Asset folder.
4. PlistParser.java - Activity has button to trigger the parsing event.  On Parse Button click, Application will fetch plist file from assets and pass the XML string content to ParsePlist class.

Download Source  


1. sample.plist - Asmple plist file

 
  gameid
  1
  drawid
  5544
  dname
  9623
  date
  9999-01-01 00:00:00
  prize
  1490000.00
  sels
  
 
 
  gameid
  2
  drawid
  5546
  dname
  753
  date
  9999-01-01 00:00:00
  prize
  20030000.00
  sels
  
 
 
  gameid
  11
  drawid
  5545
  dname
  3185
  date
  2012-01-28 00:00:00
  prize
  0.00
  sels
  
 
 
  gameid
  11
  drawid
  5505
  dname
  3183
  date
  2012-01-21 00:00:00
  prize
  0.00
  sels
  
 
 
  gameid
  11
  drawid
  5498
  dname
  3181
  date
  2012-01-14 00:00:00
  prize
  0.00
  sels
  
 
 
  gameid
  11
  drawid
  5485
  dname
  3179
  date
  2012-01-07 00:00:00
  prize
  0.00
  sels
  
 
 
  gameid
  11
  drawid
  5479
  dname
  3177
  date
  2011-12-31 00:00:00
  prize
  0.00
  sels
  
 
 
  gameid
  11
  drawid
  5472
  dname
  3175
  date
  2011-12-24 00:00:00
  prize
  0.00
  sels
  
 
 
  gameid
  11
  drawid
  5434
  dname
  3173
  date
  2011-12-17 00:00:00
  prize
  0.00
  sels
  
 
 
  gameid
  11
  drawid
  5405
  dname
  3171
  date
  2011-12-10 00:00:00
  prize
  0.00
  sels
  
 
    


2. PlistParser.java - Activity has button to trigger Plist parsing.

package com.kpbird.plistparser;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Iterator;

import com.kpbird.plist.DataModel;
import com.kpbird.plist.ParsePlist;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class PlistParser extends Activity implements OnClickListener {

 Button btnStart;
 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  btnStart = (Button) findViewById(R.id.button1);
  btnStart.setOnClickListener(this);
 }

 
 /// Read plist from Assets
 private String readPlistFromAssets() {
  StringBuffer sb = new StringBuffer();
  BufferedReader br=null;
  try {
    br = new BufferedReader(new InputStreamReader(getAssets().open("sample.plist"))); 
   String temp;
   while ((temp = br.readLine()) != null)
    sb.append(temp);
  } catch (IOException e) {
   e.printStackTrace();
  } finally {
   try {
    br.close(); // stop reading
   } catch (IOException ex) {
    ex.printStackTrace();
   }
  }
  return sb.toString();
 }


 // Start Parsing on Button Click
 public void onClick(View v) {
  // Read Plist content
  String xml = readPlistFromAssets();
  // create object of Parser Class
  ParsePlist pp = new ParsePlist();
  // parse Plist and fill in plist array
  ArrayList plist = pp.parsePlist(xml);
  // Print ArrayList
  Iterator i = plist.iterator();
  while(i.hasNext()){
   DataModel d = i.next();
   Log.i("Plist","=========================");
   Log.i("Plist","Date " + d.getDate());
   Log.i("Plist","DrawName " + d.getDrawName());
   Log.i("Plist","Prize " + d.getPrize());
   Log.i("Plist","Sels " + d.getSels());
   Log.i("Plist","Draw Id " + d.getDrawId());
   Log.i("Plist","Game Id " + d.getGameId());
  }
  Toast.makeText(this, "Parsing completed please check logcat...", Toast.LENGTH_LONG).show();
  
 }

}

3. DataModel.java - It will store Plist data. you need to modify this class according to your requirement.

package com.kpbird.plist;

public class DataModel {
 
 private int gameId;
 private int drawId;
 private String drawName;
 private String date;
 private String prize;
 private String sels;
 
 public int getGameId() {
  return gameId;
 }
 public void setGameId(int gameId) {
  this.gameId = gameId;
 }
 public int getDrawId() {
  return drawId;
 }
 public void setDrawId(int drawId) {
  this.drawId = drawId;
 }
 public String getDrawName() {
  return drawName;
 }
 public void setDrawName(String drawName) {
  this.drawName = drawName;
 }
 public String getDate() {
  return date;
 }
 public void setDate(String date) {
  this.date = date;
 }
 public String getPrize() {
  return prize;
 }
 public void setPrize(String prize) {
  this.prize = prize;
 }
 public String getSels() {
  return sels;
 }
 public void setSels(String sels) {
  this.sels = sels;
 }
}

4. ParsePlist.java - Class having method to parse plist. Create object of this class and pass plist content as string in method "parsePlist" It will return ArrayList of DataModel object.

package com.kpbird.plist;

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

public class ParsePlist {

 
 // parse Plist and fill in arraylist
 public ArrayList parsePlist(String xml) {
  final ArrayList dataModels = new ArrayList();
  //Get the xml string from assets
  
        final Document doc = XMLfromString(xml);
        
        final NodeList nodes_array = doc.getElementsByTagName("array");
  
  //Fill in the list items from the XML document
  for ( int index = 0; index < nodes_array.getLength(); index++ ) {
   
   final Node node = nodes_array.item(index);
   
   if ( node.getNodeType() == Node.ELEMENT_NODE ) {
    final Element e = (Element)nodes_array.item(index);
    
    final NodeList nodeKey = e.getElementsByTagName("key");
    final NodeList nodeValue = e.getElementsByTagName("string");
    DataModel model = new DataModel();
    
    for (int i=0; i < nodeValue.getLength(); i++) {
     
     final Element eleKey = (Element)nodeKey.item(i);
     final Element eleString = (Element)noveValue.item(i);
     
     
     if ( eleString != null ) {
      
      String strValue = getValue(eleString, "string");
      
      if(getValue(eleKey, "key").equals("gameid")) {
       model = new DataModel();
       model.setGameId(Integer.parseInt(strValue));
      } else if(getValue(eleKey, "key").equals("drawid")) {
       model.setDrawId(Integer.parseInt(strValue));
      } else if(getValue(eleKey, "key").equals("dname")) {
       model.setDrawName(strValue);
      } else if(getValue(eleKey, "key").equals("date")) {
       model.setDate(strValue);
      } else if(getValue(eleKey, "key").equals("prize")) {
       model.setPrize(strValue);
      } else if(getValue(eleKey, "key").equals("sels")) {
       if ( strValue == null ) {
        strValue = "";
       }
       model.setSels(strValue);
       dataModels.add(model);
      }
     }
    }
   }
  }
  return dataModels;
 }
 
 // Create xml document object from XML String
 private  Document XMLfromString(String xml) {
  Document doc = null;

  DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
  try {
   DocumentBuilder db = dbf.newDocumentBuilder();
   InputSource is = new InputSource();
   is.setCharacterStream(new StringReader(xml));
   doc = db.parse(is);
  } catch (ParserConfigurationException e) {
   System.out.println("XML parse error: " + e.getMessage());
   return null;
  } catch (SAXException e) {
   System.out.println("Wrong XML file structure: " + e.getMessage());
   return null;
  } catch (IOException e) {
   System.out.println("I/O exeption: " + e.getMessage());
   return null;
  }

  return doc;
 }

 // fetch value from Text Node only
 private   String getElementValue(Node elem) {
  Node kid;
  if (elem != null) {
   if (elem.hasChildNodes()) {
    for (kid = elem.getFirstChild(); kid != null; kid = kid.getNextSibling()) {
     if (kid.getNodeType() == Node.TEXT_NODE) {
      return kid.getNodeValue();
     }
    }
   }
  }
  return "";
 }

 /// Fetch value from XML Node
 private   String getValue(Element item, String str) {
  NodeList n = item.getElementsByTagName(str);
  return getElementValue(n.item(0));
 }
} 
 

3 comments:

  1. How can I use this to parse an array of arrays filled with strings?

    ReplyDelete
  2. Nice and clear, but it doesnt write elements into LogCat for me.
    i.hasNext() is always false, why?

    ReplyDelete
  3. It works on android version 2.3.5 but not on 4.0.3, why?

    ReplyDelete