Android Xml parsing with XmlPullParser and loading to ListView – Example

September 6, 2012
By

According to Android documentation, XmlPullParser is the efficient and maintainable way to parse XML in Android. In this article, we will parse  xml data using XmlPullParser and load that data into a listview. Since xml parsing is a complex and time consuming ( depends on the xml data )  process, we are doing it in a non ui thread using AsyncTask object.

Our XML data contain a set of countries with their name, capital, path to flag image, language, currency and currency code. After parsing, the country details and the flag image will be displayed in listview using a custom layout.

This application is developed in Eclipse ( 4.2.0 ) with ADT plugin ( 20.0.3 ) and Android SDK ( R20.0.3 ) .


1. Create an Android application project namely “ListViewWithXMLPullParser”

Create a new Android Application Project

Figure 1 : Create a new Android Application Project


2. Design application launcher icon

Design an Application launcher icon

Figure 2 : Design an Application launcher icon


3. Create a blank activity to define MainActivity class

Create a blank activity

Figure 3 : Create a blank activity


4. Enter MainActivity details

Enter MainActivity Details

Figure 4 : Enter MainActivity Details


5. Create a new folder namely drawable under the folder res


6. Download and extract the given below zip file to the drawable folder


7. Update the file res/values/strings.xml


<resources>
    <string name="app_name">ListViewWithXMLPullParser</string>
    <string name="hello_world">Hello world!</string>
    <string name="menu_settings">Settings</string>
    <string name="title_activity_main">XmlPullParser Demo</string>
    <string name="str_iv_flag">Flag</string>
</resources>


8. Update the layout of the MainActivity class in the file res/layout/activity_main.xml


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <ListView
        android:id="@+id/lv_countries"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        tools:context=".MainActivity" />

</RelativeLayout>


9. Create a layout for the listview items in the file res/layout/lv_layout.xml


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <TextView
        android:id="@+id/tv_country"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:textSize="20dp" />

    <ImageView
        android:id="@+id/iv_flag"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/tv_country"
        android:layout_centerVertical="true"
        android:padding="4dp"
        android:contentDescription="@string/str_iv_flag" />

    <TextView
        android:id="@+id/tv_country_details"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/iv_flag"
        android:layout_below="@id/tv_country" />

</RelativeLayout>


10.Create a class, to parse the xml data using XmlPullParser


package in.wptrafficanalyzer.listviewwithxmlpullparser;

import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import android.util.Xml;

public class CountryXmlParser {

    private static final String ns = null;

    /** This is the only function need to be called from outside the class */
    public List<HashMap<String, String>> parse(Reader reader)
            throws XmlPullParserException, IOException{
        try{
            XmlPullParser parser = Xml.newPullParser();
            parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
            parser.setInput(reader);
            parser.nextTag();
            return readCountries(parser);
        }finally{
        }
    }

    /** This method read each country in the xml data and add it to List */
    private List<HashMap<String, String>> readCountries(XmlPullParser parser)
            throws XmlPullParserException,IOException{

        List<HashMap<String, String>> list = new ArrayList<HashMap<String,String>>();

        parser.require(XmlPullParser.START_TAG, ns, "countries");

        while(parser.next() != XmlPullParser.END_TAG){
            if(parser.getEventType() != XmlPullParser.START_TAG){
                continue;
            }

            String name = parser.getName();
            if(name.equals("country")){
                list.add(readCountry(parser));
            }
            else{
                skip(parser);
            }
        }
        return list;
    }

    /** This method read a country and returns its corresponding HashMap construct */
    private HashMap<String, String> readCountry(XmlPullParser parser)
            throws XmlPullParserException, IOException{

        parser.require(XmlPullParser.START_TAG, ns, "country");

        String countryName = parser.getAttributeValue(ns, "name");
        String flag = parser.getAttributeValue(ns, "flag");
        String language="";
        String capital="";
        String currencyCode="";
        String currency="";

        while(parser.next() != XmlPullParser.END_TAG){
            if(parser.getEventType() != XmlPullParser.START_TAG){
                continue;
            }

            String name = parser.getName();

            if(name.equals("language")){
                language = readLanguage(parser);
            }else if(name.equals("capital")){
                capital = parser.getAttributeValue(ns, "city");
                readCapital(parser);
            }else if(name.equals("currency")){
                currencyCode = parser.getAttributeValue(ns, "code");
                currency = readCurrency(parser);
            }else{
                skip(parser);
            }
        }

        String details =    "Language : " + language + "\n" +
                            "Capital : " + capital + "\n" +
                            "Currency : " + currency + "(" + currencyCode + ")";

        HashMap<String, String> hm = new HashMap<String, String>();
        hm.put("country", countryName);
        hm.put("flag", flag);
        hm.put("details",details);

        return hm;
    }

    /** Process language tag in the xml data */
    private String readLanguage(XmlPullParser parser)
            throws IOException, XmlPullParserException {
        parser.require(XmlPullParser.START_TAG, ns, "language");
        String language = readText(parser);
        return language;
    }

    /** Process Capital tag in the xml data */
    private void readCapital(XmlPullParser parser)
            throws IOException, XmlPullParserException {
        parser.require(XmlPullParser.START_TAG, ns, "capital");
        parser.nextTag();
    }

    /** Process Currency tag in the xml data */
    private String readCurrency(XmlPullParser parser)
            throws IOException, XmlPullParserException {
        parser.require(XmlPullParser.START_TAG, ns, "currency");
        String currency = readText(parser);
        return currency;
    }

    /** Getting Text from an element */
    private String readText(XmlPullParser parser)
            throws IOException, XmlPullParserException{
        String result = "";
        if(parser.next()==XmlPullParser.TEXT){
            result = parser.getText();
            parser.nextTag();
        }
        return result;
    }

    private void skip(XmlPullParser parser)
            throws XmlPullParserException, IOException {
        if (parser.getEventType() != XmlPullParser.START_TAG) {
           throw new IllegalStateException();
        }
        int depth = 1;
        while (depth != 0) {
            switch (parser.next()) {
                case XmlPullParser.END_TAG:
                    depth--;
                    break;
                case XmlPullParser.START_TAG:
                    depth++;
                    break;
            }
        }
    }
}


11. Update the MainActivity class in the file src/in/wptrafficanalyzer/listviewwithxmlpullparser/MainActivity.java


package in.wptrafficanalyzer.listviewwithxmlpullparser;

import java.io.StringReader;
import java.util.HashMap;
import java.util.List;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.widget.ListView;
import android.widget.SimpleAdapter;

public class MainActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        /** This is the XML data to be parsed */
        String xmlData = "<countries>" +
                            "<country name='India' flag='"+Integer.toString(R.drawable.india) +"'>" +
                                "<language>Hindi</language>" +
                                "<capital city='New Delhi' />" +
                                "<currency code='INR'>Indian Rupee</currency>" +
                            "</country>" +

                            "<country name='Pakistan' flag='"+Integer.toString(R.drawable.pakistan) +"'>" +
                                "<language>Urdu</language>" +
                                "<capital city='Islamabad' />" +
                                "<currency code='PKR'>Pakistani Rupee</currency>" +
                            "</country>" +

                            "<country name='Sri Lanka' flag='"+Integer.toString(R.drawable.srilanka) +"'>" +
                                "<language>Sinhala</language>" +
                                "<capital city='Sri Jayawardenapura Kotte' />" +
                                "<currency code='LKR'>Sri Lankan Rupee</currency>" +
                            "</country>" +

                            "<country name='China' flag='"+Integer.toString(R.drawable.china) +"'>" +
                                "<language>Chineese</language>" +
                                "<capital city='Beijing' />" +
                                "<currency code='CNY'>Renminbi</currency>" +
                            "</country>" +

                            "<country name='Bangladesh' flag='"+Integer.toString(R.drawable.bangladesh) +"'>" +
                                "<language>Bangla</language>" +
                                "<capital city='Dhaka' />" +
                                "<currency code='BDT'>Taka</currency>" +
                            "</country>" +

                            "<country name='Nepal' flag='"+Integer.toString(R.drawable.nepal) +"'>" +
                                "<language>Nepal Bhasa</language>" +
                                "<capital city='Kathmandu' />" +
                                "<currency code='NPR'>Nepalese rupee</currency>" +
                            "</country>" +

                            "<country name='Afghanistan' flag='"+Integer.toString(R.drawable.afghanistan) +"'>" +
                                "<language>Dari Persian</language>" +
                                "<capital city='Kabul' />" +
                                "<currency code='AFN'>Afghani</currency>" +
                            "</country>" +

                            "<country name='North Korea' flag='"+Integer.toString(R.drawable.nkorea) +"'>" +
                                "<language>Korean</language>" +
                                "<capital city='Pyongyang' />" +
                                "<currency code='KPW'>North Korean won</currency>" +
                            "</country>" +

                            "<country name='South Korea' flag='"+Integer.toString(R.drawable.skorea) +"'>" +
                                "<language>Korean</language>" +
                                "<capital city='Seoul' />" +
                                "<currency code='KRW'>South Korean won</currency>" +
                            "</country>" +

                            "<country name='Japan' flag='"+Integer.toString(R.drawable.japan) +"'>" +
                                "<language>Japanese</language>" +
                                "<capital city='Tokyo' />" +
                                "<currency code='JPY'>Yen</currency>" +
                            "</country>" +
                        "</countries>";

        /** The parsing of the xml data is done in a non-ui thread */
        ListViewLoaderTask listViewLoaderTask = new ListViewLoaderTask();

        /** Start parsing xml data */
        listViewLoaderTask.execute(xmlData);

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

    private class ListViewLoaderTask extends AsyncTask<String, Void, SimpleAdapter>{

        /** Doing the parsing of xml data in a non-ui thread */
        @Override
        protected SimpleAdapter doInBackground(String... xmlData) {
            StringReader reader = new StringReader(xmlData[0]);

            CountryXmlParser countryXmlParser = new CountryXmlParser();

            List<HashMap<String, String>> countries = null;

            try{
                /** Getting the parsed data as a List construct */
                countries = countryXmlParser.parse(reader);
            }catch(Exception e){
                Log.d("Exception",e.toString());
            }

            /** Keys used in Hashmap */
            String[] from = { "country","flag","details"};

            /** Ids of views in listview_layout */
            int[] to = { R.id.tv_country,R.id.iv_flag,R.id.tv_country_details};

            /** Instantiating an adapter to store each items
            *  R.layout.listview_layout defines the layout of each item
            */
            SimpleAdapter adapter = new SimpleAdapter(getBaseContext(), countries, R.layout.lv_layout, from, to);

            return adapter;
        }

        @Override
        protected void onPostExecute(SimpleAdapter adapter) {

            /** Getting a reference to listview of main.xml layout file */
            ListView listView = ( ListView ) findViewById(R.id.lv_countries);

            /** Setting the adapter containing the country list to listview */
            listView.setAdapter(adapter);
        }
    }
}


12. Screenshot of the application

ListVIew with XML data parsed by XmlPullParser

Figure 5 : ListVIew with XML data parsed by XmlPullParser


13. Download


14. Reference

http://developer.android.com/guide/index.html


How to hire me?

I am George Mathew, working as software architect and Android app developer at wptrafficanalyzer.in

You can hire me on hourly basis or on project basis for Android applications development.

For hiring me, please mail your requirements to info@wptrafficanalyzer.in.

My other blogs
store4js.blogspot.com


Android Knowledge Quiz

Ready to test your knowledge in Android? Take this quiz :



Tags: , , , , , , , ,

2 Responses to Android Xml parsing with XmlPullParser and loading to ListView – Example

  1. Christian on July 31, 2013 at 8:48 am

    Nice tutorial. Keep it up buddy! :)

  2. hadi on February 1, 2016 at 11:14 am

    very nice code,thank u

Leave a Reply

Your email address will not be published. Required fields are marked *

Be friend at g+

Subscribe for Lastest Updates

FBFPowered by ®Google Feedburner