XML Parsing using SAXParser – Android

Webservices are one of the effective way of transferring information from server to mobile apps. The webservices may use XML or JSON formats for the purpose.

This tutorial is about parsing information available at http://pcsalt.com/postservice/?format=xml. And, the end result will be an Android app having a list of posts on Android, and clicking on the list item will open the linked page.

Following XML is an abstract from above URL. First we determine what tags are there in XML and then we would parse to extract and display this information.


    
        Add EditText Programmatically - Android
        http://pcsalt.com/?p=249
        2013-01-26 01:05:35
    
    
        Android SQLite Database - Part 1/2
        http://pcsalt.com/?p=442
        2013-04-18 23:48:59
    

So, this service have posts as main tag, i.e., complete XML is enclosed inside this tag. And, the post tag has all information related with each post. The information enclosed are:

  • Post Title (post_title),
  • Guid (guid), and
  • Publish Date (post_date).

First create Android Application project by following the steps in Create Andriod Application Project in Android Studio Continued with following values

Application Name CustomListViewDemo
Package Name pcsalt.example.xmlparsingsaxdemo
Minimum SDK for Android App 8
Activity Name MainActivity
Layout Name activity_main


(adsbygoogle = window.adsbygoogle || []).push({});

Directory structure of project would be

  • java
    pcsalt.example.xmlparsingsaxdemo

    • MainActivity.java
    • PostBaseAdapter.java
    • PostValue.java
    • XMLHelper.java
  • res
    layout

    • activity_main.xml
    • list_item_post.xml

In order to parse the XML, two JAVA classes would be needed, namely

  • PostValue.java – Value holder class (consists of getters and setters) to hold the values of each post tag, and
  • XMLHelper.java – Helper class to open a stream, parse XML and store value in PostValue type object.

PostValue.java: It is a model class consists of getters/setters for title, guid, and date. The information from XML is stored in instance of this class. So, these methods will be helpful in storing and retrieving information to/from instance of this class.

package pcsalt.example.xmlparsingsaxdemo;
/**
 * A class for getters and setters for post
 * */
public class PostValue {
	String title, guid, date;
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getGuid() {
		return guid;
	}
	public void setGuid(String guid) {
		this.guid = guid;
	}
	public String getDate() {
		return date;
	}
	public void setDate(String date) {
		this.date = date;
	}
}

XMLHelper.java: This class sends request to the URL and when it gets XML in response SAXParser helps parse the XML.

package pcsalt.example.xmlparsingsaxdemo;
import android.util.Log;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
public class XMLHelper extends DefaultHandler {
    /**
     * The URL to be parsed
     */
    private String URL_MAIN = "http://pcsalt.com/postservice/?format=xml";
    String TAG = "XMLHelper";
    Boolean currTag = false;
    String currTagVal = "";
    private PostValue post = null;
    private ArrayList posts = new ArrayList();
    public ArrayList getPostsList() {
        return this.posts;
    }
    /**
     * Method to read XML from {@link pcsalt.example.xmlparsingsaxdemo.XMLHelper#URL_MAIN}
     */
    public void get() {
        try {
            SAXParserFactory factory = SAXParserFactory.newInstance();
            SAXParser mSaxParser = factory.newSAXParser();
            XMLReader mXmlReader = mSaxParser.getXMLReader();
            mXmlReader.setContentHandler(this);
            InputStream mInputStream = new URL(URL_MAIN).openStream();
            mXmlReader.parse(new InputSource(mInputStream));
        } catch (Exception e) {
            // Exceptions can be handled for different types
            // But, this is about XML Parsing not about Exception Handling
            Log.e(TAG, "Exception: " + e.getMessage());
        }
    }
    // This method receives notification character data inside an element
    // e.g. Add EditText Pragmatically - Android
    // It will be called to read "Add EditText Pragmatically - Android"
    @Override
    public void characters(char[] ch, int start, int length)
            throws SAXException {
        if (currTag) {
            currTagVal = currTagVal + new String(ch, start, length);
            currTag = false;
        }
    }
    // Receives notification of end of element
    // e.g. Add EditText Pragmatically - Android
    // It will be called when  is encountered
    @Override
    public void endElement(String uri, String localName, String qName)
            throws SAXException {
        currTag = false;
        if (localName.equalsIgnoreCase("post_title"))
            post.setTitle(currTagVal);
        else if (localName.equalsIgnoreCase("guid"))
            post.setGuid(currTagVal);
        else if (localName.equalsIgnoreCase("post_date"))
            post.setDate(currTagVal);
        else if (localName.equalsIgnoreCase("post"))
            posts.add(post);
    }
    // Receives notification of start of an element
    // e.g. Add EditText Pragmatically - Android
    // It will be called when  is encountered
    @Override
    public void startElement(String uri, String localName, String qName,
                             Attributes attributes) throws SAXException {
        Log.i(TAG, "TAG: " + localName);
        currTag = true;
        currTagVal = "";
        // Whenever  element is encountered it will create new object of PostValue
        if (localName.equals("post"))
            post = new PostValue();
    }
}

MainActivity.java: This is used for displaying the parsed XML response. Since, the network operations must not be performed on main-thread, that’s why we are using AsyncTask to request the XML and parse information in the AsyncTask. After successful parsing we will be displaying result in a ListView.

package pcsalt.example.xmlparsingsaxdemo;
import android.app.ProgressDialog;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import java.util.ArrayList;
public class MainActivity extends ActionBarActivity {
    ListView lvPcsPost;
    ArrayList postValueArrayList;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        lvPcsPost = (ListView) findViewById(R.id.lvPcsPost);
        lvPcsPost.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView parent, View view, int position, long id) {
                if (postValueArrayList != null && postValueArrayList.size() > 0) {
                    Intent intentShowPost = new Intent(Intent.ACTION_VIEW, Uri.parse(postValueArrayList.get(position).getGuid()));
                    startActivity(intentShowPost);
                }
            }
        });
        new PostAsync().execute();
    }
    class PostAsync extends AsyncTask {
        ProgressDialog pd;
        XMLHelper helper;
        @Override
        protected void onPreExecute() {
            pd = ProgressDialog.show(MainActivity.this, "PCSalt", "Loading posts for PCSalt.com ...", true, false);
        }
        @Override
        protected Void doInBackground(Void... arg0) {
            helper = new XMLHelper();
            helper.get();
            postValueArrayList = helper.getPostsList();
            return null;
        }
        @Override
        protected void onPostExecute(Void result) {
            PostBaseAdapter postBaseAdapter = new PostBaseAdapter(MainActivity.this, postValueArrayList);
            lvPcsPost.setAdapter(postBaseAdapter);
            pd.dismiss();
        }
    }
}

PostBaseAdapter: It is an adapter class to initialise and maintain the list items. It’s getView() method is responsible for instantiating new list item on scroll. We are going to reuse the already created list item to display new post.

When ListView is scrolled up or down, new list item needs to be created. It will consume memory to always create a new list item on scroll. So, we are going to create only those list item which are visible at a time (say 6 list items), and reuse these list items during scroll. It is handled by checking if convertView is null or not. If it is not null then list item view already exists, then we will reuse that view, in lieu of creating new list item view.

package pcsalt.example.xmlparsingsaxdemo;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import java.util.ArrayList;
/**
 * Created by Krrishnaaaa on Jan 01, 2015
 */
public class PostBaseAdapter extends BaseAdapter {
    private LayoutInflater layoutInflater;
    private ArrayList postValueArrayList;
    public PostBaseAdapter(Context context, ArrayList postValueArrayList) {
        this.layoutInflater = LayoutInflater.from(context);
        this.postValueArrayList = postValueArrayList;
    }
    @Override
    public int getCount() {
        return postValueArrayList.size();
    }
    @Override
    public PostValue getItem(int position) {
        return postValueArrayList.get(position);
    }
    @Override
    public long getItemId(int position) {
        return 0;
    }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder;
        if (convertView == null) {
            convertView = layoutInflater.inflate(R.layout.list_item_post, parent, false);
            viewHolder = new ViewHolder(convertView);
            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }
        PostValue postValue = getItem(position);
        viewHolder.tvTitle.setText(postValue.getTitle());
        viewHolder.tvPublishDate.setText(postValue.getDate());
        return convertView;
    }
    private class ViewHolder {
        TextView tvTitle, tvPublishDate;
        public ViewHolder(View item) {
            tvTitle = (TextView) item.findViewById(R.id.tvTitle);
            tvPublishDate = (TextView) item.findViewById(R.id.tvPublishDate);
        }
    }
}

activity_main.xml: This is the layout for MainActivity class. It contains a ListView. In this ListView, the XML response will be displayed. Clicking on list item will open the selected post in web browser.


list_item_post.xml: This layout is for displaying the post list, after parsing the XML. It contains two TextView. First will display the title of post, and second will display the publish date.



    
    

This application would need permission to connect to Internet. So, the manifest file should be modified
AndroidManifest.xml



    
    
    
        
            
                
                
            
        
    

build.gradle

apply plugin: 'com.android.application'
android {
    compileSdkVersion 22
    buildToolsVersion "22.0.1"
    defaultConfig {
        applicationId "pcsalt.example.xmlparsingsaxdemo"
        minSdkVersion 8
        targetSdkVersion 22
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:22.2.0'
}

Download Source:
github-logo-transparent
Video Tutorial : This tutorial was created with Eclipse and to display the XML response in a TextView inside ScrollView. The video is still valid.

In case you have any trouble, feel free to post comment. I will try my best to response at the earliest.