XML parsing could be one of the most basic requirement on your Android application. In today’s tutorial, we are going to read XML files using three input sources. There can be three sources of your XML:
1. XML from device SD Card. Your dynamic XML file could be downloaded first for offline use.
2. XML from a URL. You could be parsing data from your online database or RSS feed. Works if device is online only.
3. XML from your app’s assets folder. Your XML file is not dynamic so it is better to put it in the asset’s folder where it cannot be change.
By the way, we’ll be using SAX parser here. I think that for mobile apps, SAX parser is better to use than DOM parser.
DOM parser consumes more memory because it loads the whole XML data to the device memory while SAX parser does an event driven approach. SAX parser processes each line of the XML without loading it to the device memory first.
Our XML structure looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<Contents>
<Owners>
<Owner>
<Name>Joselito Dimaculangan</Name>
<Age>16</Age>
<EmailAddress>joselito123@gmail.com</EmailAddress>
</Owner>
<Owner>
<Name>Noemi De Galileo</Name>
<Age>14</Age>
<EmailAddress>noemi111@gmail.com</EmailAddress>
</Owner>
</Owners>
<Dogs>
<Dog>
<Name>Barky</Name>
<Birthday>June 29, 2012</Birthday>
</Dog>
<Dog>
<Name>Jumbo</Name>
<Birthday>December 30, 2012</Birthday>
</Dog>
</Dogs>
</Contents>
MainActivity.java code – Here you can change the value of x to 1,2 or 3 to change the input source. Read comments on code.
package com.example.androidparsexml;
import java.io.File;
import java.io.FileInputStream;
import java.net.URL;
import java.util.Iterator;
import java.util.List;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.app.Activity;
public class MainActivity extends Activity {
public static final String LOG_TAG = "MainActivity.java";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
// parse our XML
new parseXmlAsync().execute();
} catch (NullPointerException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
/*
* @We are using an AsyncTask to avoid
* android.os.NetworkOnMainThreadException when parsing from a URL
*
* @If you don't know a thing about AsyncTasks,there are a lot of excellent
* tutorial out there, see this thread
*/
private class parseXmlAsync extends AsyncTask<String, String, String> {
@Override
protected String doInBackground(String... strings) {
try {
/*
* You may change the value of x to try different sources of XML
*
* @1 = XML from SD Card
*
* @2 = XML from URL
*
* @3 = XML from assets folder
*/
int x = 2;
// initialize our input source variable
InputSource inputSource = null;
// XML from sdcard
if (x == 1) {
// make sure sample.xml is in your root SD card directory
File xmlFile = new File(
Environment.getExternalStorageDirectory()
+ "/sample.xml");
FileInputStream xmlFileInputStream = new FileInputStream(
xmlFile);
inputSource = new InputSource(xmlFileInputStream);
}
// XML from URL
else if (x == 2) {
// specify a URL
// make sure you are connected to the internet
URL url = new URL(
"http://demo.codeofaninja.com/AndroidXml/sample.xml");
inputSource = new InputSource(url.openStream());
}
// XML from assets folder
else if (x == 3) {
inputSource = new InputSource(getAssets()
.open("sample.xml"));
}
// instantiate SAX parser
SAXParserFactory saxParserFactory = SAXParserFactory
.newInstance();
SAXParser saxParser = saxParserFactory.newSAXParser();
// get the XML reader
XMLReader xmlReader = saxParser.getXMLReader();
// prepare and set the XML content or data handler before
// parsing
XmlContentHandler xmlContentHandler = new XmlContentHandler();
xmlReader.setContentHandler(xmlContentHandler);
// parse the XML input source
xmlReader.parse(inputSource);
// put the parsed data to a List
List<ParsedDataSet> parsedDataSet = xmlContentHandler
.getParsedData();
// we'll use an iterator so we can loop through the data
Iterator<ParsedDataSet> i = parsedDataSet.iterator();
ParsedDataSet dataItem;
while (i.hasNext()) {
dataItem = (ParsedDataSet) i.next();
/*
* parentTag can also represent the main type of data, in
* our example, "Owners" and "Dogs"
*/
String parentTag = dataItem.getParentTag();
Log.v(LOG_TAG, "parentTag: " + parentTag);
if (parentTag.equals("Owners")) {
Log.v(LOG_TAG, "Name: " + dataItem.getName());
Log.v(LOG_TAG, "Age: " + dataItem.getAge());
Log.v(LOG_TAG,
"EmailAddress: " + dataItem.getEmailAddress());
}
else if (parentTag.equals("Dogs")) {
Log.v(LOG_TAG, "Name: " + dataItem.getName());
Log.v(LOG_TAG, "Birthday: " + dataItem.getBirthday());
}
}
} catch (NullPointerException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(String lenghtOfFile) {
// your do stuff after parsing the XML
}
}
}
XmlContentHandler.java – We’ll extend the default handler.
package com.example.androidparsexml;
import java.util.ArrayList;
import java.util.List;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import android.util.Log;
public class XmlContentHandler extends DefaultHandler {
private static final String LOG_TAG = "XmlContentHandler";
// used to track of what tags are we
private boolean inOwner = false;
private boolean inDog = false;
// accumulate the values
private StringBuilder mStringBuilder = new StringBuilder();
// new object
private ParsedDataSet mParsedDataSet = new ParsedDataSet();
// the list of data
private List<ParsedDataSet> mParsedDataSetList = new ArrayList<ParsedDataSet>();
/*
* Called when parsed data is requested.
*/
public List<ParsedDataSet> getParsedData() {
Log.v(LOG_TAG, "Returning mParsedDataSetList");
return this.mParsedDataSetList;
}
// Methods below are built in, we just have to do the tweaks.
/*
* @Receive notification of the start of an element.
*
* @Called in opening tags such as <Owner>
*/
@Override
public void startElement(String namespaceURI, String localName,
String qName, Attributes atts) throws SAXException {
if (localName.equals("Owner")) {
// meaning new data object will be made
this.mParsedDataSet = new ParsedDataSet();
this.inOwner = true;
}
else if (localName.equals("Dog")) {
this.mParsedDataSet = new ParsedDataSet();
this.inDog = true;
}
}
/*
* @Receive notification of the end of an element.
*
* @Called in end tags such as </Owner>
*/
@Override
public void endElement(String namespaceURI, String localName, String qName)
throws SAXException {
// Owners
if (this.inOwner == true && localName.equals("Owner")) {
this.mParsedDataSetList.add(mParsedDataSet);
mParsedDataSet.setParentTag("Owners");
this.inOwner = false;
}
else if (this.inOwner == true && localName.equals("Name")) {
mParsedDataSet.setName(mStringBuilder.toString().trim());
}
else if (this.inOwner == true && localName.equals("Age")) {
mParsedDataSet.setAge(mStringBuilder.toString().trim());
}
else if (this.inOwner == true && localName.equals("EmailAddress")) {
mParsedDataSet.setEmailAddress(mStringBuilder.toString().trim());
}
// Dogs
if (this.inDog == true && localName.equals("Dog")) {
this.mParsedDataSetList.add(mParsedDataSet);
mParsedDataSet.setParentTag("Dogs");
this.inDog = false;
}
else if (this.inDog == true && localName.equals("Name")) {
mParsedDataSet.setName(mStringBuilder.toString().trim());
}
else if (this.inDog == true && localName.equals("Birthday")) {
mParsedDataSet.setBirthday(mStringBuilder.toString().trim());
}
// empty our string builder
mStringBuilder.setLength(0);
}
/*
* @Receive notification of character data inside an element.
*
* @Gets be called on the following structure: <tag>characters</tag>
*/
@Override
public void characters(char ch[], int start, int length) {
// append the value to our string builder
mStringBuilder.append(ch, start, length);
}
}
ParsedDataSet.java – You can use your own object class if the XML you’re parsing is for a more specific data object. For example, you are parsing only for “Owners” and NOT “Owners & Dogs” like what we have.
package com.example.androidparsexml;
public class ParsedDataSet {
private String parentTag = null;
private String name = null;
private String age = null;
private String emailAddress = null;
private String birthday = null;
// parent tag
public String getParentTag() {
return parentTag;
}
public void setParentTag(String parentTag) {
this.parentTag = parentTag;
}
// name
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// age
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
// emailAddress
public String getEmailAddress() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
// birthday
public String getBirthday() {
return birthday;
}
public void setBirthday(String name) {
this.birthday = name;
}
}
Our AndroidManifest.xml will have internet permissions because we use a URL input
<uses-permission android:name="android.permission.INTERNET" />
Our code output on the device look simply like this:



6 responses to “Android XML Parser Example with XML from SD Card, URL or Assets”
You repeated the XmlContentHandler’s code where it should be ParsedDataSet’s code.
So, the faster XML parser is SAX?
Hey @Ollie, yup, please consider this answer too http://stackoverflow.com/a/15608688/827418
You still have twice the same code in your post…
Oh I’m sorry, I see it now… fixed!
Hi, When i tried this code Log.v(LOG_TAG, “Name: ” + dataItem.getName()); gives me the right name value on Log. But when i tried if( dataItem.getName()==”John”) name value seems like {java.lang.String@1234}”John” on wathc and if statement gives me false. can you help with that.
Hi Mike Dalisay, you cant post a sample with loop disable? I want to disable loop i dont have multiples “Owner”.