
Parsing XML from the internet is a pretty common requirement on any platform. There are numerous ways to accomplish this task on every language out there, and the Android platform is no exception. On the Android, this is accomplished using SAXParser, a serial access parser API for XML. SAXParser functions as a stream parser, with an event-driven API, using callback methods that trigger everytime events occur during the reading.
The majority of the work is done by a SAX-Handler. The SAXParser will walk through the XML file from beginning to end (hence parsing is always unidirectional) and calls appropriate handler methods along the way. For this exercise, we will create a Handler that extends org.xml.sax.helpers.DefaultHandler and overrides the necessary methods.
On the start/end of each document, the following methods get called:
public void startDocument() throws SAXException {}
public void endDocument() throws SAXException {}
When the Parser reaches an opening tag, like <exampletag name=“labs”>, the following method gets called:
public void startElement(String namespaceURI, String localName, String qName,
Attributes atts) throws SAXException {}
In this case, localName will be "exampletag". The atts variable will hold any associated attribute information: atts.getValue("name") will return "labs".
When we reach a closing tag, like </exampletag>, the equivalent closing method gets called:
public void endElement(String namespaceURI, String localName, String qName)
throws SAXException {}
In the same manner, localName will be "exampletag".
In between an opening and closing tag, there can be a string, like <exampletag>here is some content</exampletag>. The SAXParser reads in the string, one character at a time, but buffers method calls to the handler:
public void characters(char ch[], int start, int length) {}
The ch[] array holds a buffer of characters that the SAXParser has read in, but the only relevant chunk is given by the start and length values. With large enough strings, the characters() method may be called multiple times within a single block of character data. This is a place where I personally stumbled with, as it seems many tutorials out there seem to ignore this fact, assuming the entire block is returned and end up only getting partial data.
Now that I've explained the basics of how this all works, here is some very basic example code that parses an XML doc for content of "qwerasdf" elements:
Creating a SAXParser and give it a handler:
/* Create a URL we want to load some xml-data from. */
URL url = new URL("http://example.com/example.xml");
/* Get a SAXParser from the SAXPArserFactory. */
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
/* Get the XMLReader of the SAXParser we created. */
XMLReader xr = sp.getXMLReader();
/* Create a new ContentHandler and apply it to the XML-Reader*/
ExampleHandler myExampleHandler = new ExampleHandler();
xr.setContentHandler(myExampleHandler);
/* Parse the xml-data from our URL. */
xr.parse(new InputSource(url.openStream()));
/* Parsing has finished. */
Definition of the ExampleHandler:
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class ExampleHandler extends DefaultHandler {
StringBuffer buff = null;
boolean buffering = false;
@Override
public void startDocument() throws SAXException {
// Some sort of setting up work
}
@Override
public void endDocument() throws SAXException {
// Some sort of finishing up work
}
@Override
public void startElement(String namespaceURI, String localName, String qName,
Attributes atts) throws SAXException {
if (localName.equals("qwerasdf")) {
buff = new StringBuffer("");
buffering = true;
}
}
@Override
public void characters(char ch[], int start, int length) {
if(buffering) {
buff.append(ch, start, length)
}
}
@Override
public void endElement(String namespaceURI, String localName, String qName)
throws SAXException {
if (localName.equals("blah")) {
buffering = false;
String content = buff.toString();
// Do something with the full text content that we've just parsed
}
}
}
* Please be aware that all comments are moderated.
Stelios Charmpalis | 5:01 AM October 6, 2010
Have you a tutorial on how can we produce a Custom ListView with the elements that you’re taking from the XML after the parsing?
Jim Garretson | 7:52 AM October 6, 2010
Hi Stellos, We don’t have a tutorial ourselves, but if you’d like you can take a look at the source to our Android app here:
http://qvandroid.svn.sourceforge.net/viewvc/qvandroid/
Tyler | 8:35 PM December 16, 2010
Hello,
Your code example is working great so far, thanks! However…
I am receiving this error:
===============
The method startElement(String, String, String, Attributes) of type DefaultHandler must override or implement a supertype method
===============
After much searching around, everyone suggests making sure that the Eclipse (and the project specific settings) Java Compiler is set to compiler compliance level 1.6. I have done both of these things and yet the problem persists…
Any Ideas?
Tyler | 1:28 AM December 17, 2010
Hello,
And a few hours later I found what my problem was. I was using an incorrect import on the SAX Attributes. Skipping between your tutorial and another, and I constantly overlooked the simple “make sure all your imports are correct”... unfortunately a ctrl+shift+o didn’t fix it… but making sure I had the following imports, I was all set:
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
Just like your tutorial says
Thanks!
Jim Garretson | 10:10 AM December 17, 2010
Hi Tyler,
I’m happy you were able to figure out the problem! Although the compiler compliance level is a pretty common source of errors like that, it can otherwise be tricky to debug. Thanks for coming back and letting us know how you solved it!
Joemarie Amparo | 5:04 AM February 21, 2011
Hello,
I’ve been trying to parse the xml response through HttpResponse but I can’t get it done. Can anybody help me get through this. Here’s my code:
text = (TextView)findViewById(R.id.text);
HttpURLConnection conn;
boolean result = false;
BufferedReader lResultReader = null;
try {
URI lUri = new URI(“http://api.groupjump.com/authentication.php?method=login&apikey=1111111111&username=1@1.com&password=1111111”);
// Prepares the request.
HttpClient lHttpClient = new DefaultHttpClient();
HttpGet lHttpGet = new HttpGet();
lHttpGet.setURI(lUri);
// Sends the request and read the response
HttpResponse lHttpResponse = lHttpClient.execute(lHttpGet);
InputStream lInputStream = lHttpResponse.getEntity().getContent();
/* Get a SAXParser from the SAXPArserFactory. */
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
/* Get the XMLReader of the SAXParser we created. */
XMLReader xr = sp.getXMLReader();
/* Create a new ContentHandler and apply it to the XML-Reader*/
ExampleHandler myExampleHandler = new ExampleHandler();
xr.setContentHandler(myExampleHandler);
//this is where i get error. Any alternative ways please:
xr.parse(new InputSource(lTmpResult));
/* Parsing has finished. */
/* Our ExampleHandler now provides the parsed data to us. */
ParsedExampleDataSet parsedExampleDataSet = myExampleHandler.getParsedData();
/* Set the result to be displayed in our GUI. */
text.append(parsedExampleDataSet.toString());
}
catch(MalformedURLException e){
text.setText(“1: “+e.getMessage());
e.printStackTrace();
}
catch(IOException e){
e.printStackTrace();
text.setText(“2: “+e.getMessage());
}
catch(Exception e){
e.printStackTrace();
text.setText(“3: “+e.getMessage());
}
I get error on this line:
xr.parse(new InputSource(lTmpResult));
Here is the XML format that I want to parse.
<?xml version=“1.0”?>
<callback>
<request>
<authentication>
<status> </status>
<message></message>
<content>
<id> </id>
<sessionkey></sessionkey>
</content>
</authentication>
</request>
</callback>
Please help.
Thanks,
Joemarie Amparo
nehal | 7:26 AM March 22, 2011
Hi Joemarie Amparo:
try this
xr.parse(new InputSource(lTmpResult.toString()));
Jeff | 4:24 PM April 21, 2011
Hi, I’m trying to parse an XML response from an API but I’m getting stuck. Here is what I’ve done so far
package my.example;
import java.io.IOException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class ParseExample extends Activity {
TextView tv;
String line;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//Http request
try {
HttpClient hclient = new DefaultHttpClient();
HttpGet get = new HttpGet(“http://www.google.com/ig/api?weather=Cardiff”);
HttpResponse hrep = hclient.execute(get);
HttpEntity httpEntity = hrep.getEntity();
//passing the result into a string
line = EntityUtils.toString(httpEntity);
//setting up XML parser
SAXParserFactory saxpf = SAXParserFactory.newInstance();
SAXParser saxp = saxpf.newSAXParser();
XMLReader xr = saxp.getXMLReader();
ExHandler myHandler = new ExHandler();
xr.setContentHandler(myHandler);
// passing the string into the parser
xr.parse(new InputSource(line));
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
For the Handler class here is what I’ve done
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class ExHandler extends DefaultHandler {
StringBuffer buffer = null;
Boolean buffering = false;
@Override
public void startDocument() throws SAXException {
}
@Override
public void endDocument() throws SAXException {
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
}
}
I’m stuck here because I need to understand a couple of things;
1. What settings would I do at startDocument?
2. Do I need to pass in values for uri?
3. My target XML file looks like this
<xml_api_reply version=“1”>
−
<weather module_id=“0” tab_id=“0” mobile_row=“0” mobile_zipped=“1” row=“0” section=“0”>
<forecast_conditions>
<day_of_week data=“Sun”>
<low data=“48”>
<high data=“64”>
<condition data=“Clear”>
</forecast_conditions>
</weather>
</xml_api_reply>
how would I get data from the <condition>
Joel | 5:06 AM April 27, 2011
Hi, I have a problem. I keep getting the Error:null using String str = buff.append(ch,start,length).toString() in characters method. Then in the getter/setter class I have a line: return “extractedString=” + this.extractedString.trim();
Can you please help me?
jesi | 2:37 AM May 17, 2011
can you help me parse this xml file, i need the code for this . i am new to android and java
<Quiz>
- <Topics id=“1” Topicname=“Essentials”>
- <Question number=“1” title=“True or False: Compasses always point to true north.”>
<Option Number=“A” title=“True” >
<Option Number=“B” title=“False” correct=“True” description=“False, compasses point to magnetic north � the difference varies between where you are in the world.” >
</Question>
- <Question number=“2” title=“If the moon rises before the sun has set, the illuminated side faces this direction:”>
<Option Number=“A” title=“North” >
<Option Number=“B” title=“South” >
<Option Number=“C” title=“West” correct=“True” description=“The illuminated side of the moon always points west.” >
<Option Number=“D” title=“East” >
</Question>
- <Question number=“3” title=“The stars passage over the horizon starts ___ minutes earlier each night.”>
<Option Number=“A” title=“Two minutes” >
<Option Number=“B” title=“Four minutes” correct=“True” description=“The stars passage over the horizon starts 4 minutes earlier each night.” >
<Option Number=“C” title=“Six minutes” >
<Option Number=“D” title=“Eight minutes” >
</Question>
- <Question number=“4” title=“True or False: There is no equivalent of the pole star near the South Celestial Pole.”>
<Option Number=“A” title=“True” correct=“True” description=“True, there is no equivalent of the pole star in the South Pole. However the southern cross provides a signpost to the south.” >
<Option Number=“B” title=“False” >
</Question>
- <Question number=“5” title=“True or False: The higher the clouds, the finer the weather.”>
<Option Number=“A” title=“True” correct=“True” description=“True, high clouds indicate the dry air and high pressure of fair weather.” >
<Option Number=“B” title=“False” >
</Question>
- <Question number=“6” title=“Which of the following is NOT true:”>
<Option Number=“A” title=“A red sky in the morning indicates that a storm is approaching” >
<Option Number=“B” title=“A grey morning heralds a dry day” >
<Option Number=“C” title=“A grey evening sky means that rain is imminent” >
<Option Number=“D” title=“A violet sky in the morning indicates fair weather” correct=“True” description=“A violet sky in the morning does NOT indicate fair weather.” >
</Question>
- <Question number=“7” title=“True or False: Curly haired people find their hair becomes unmanageable and tight as bad weather approaches.”>
<Option Number=“A” title=“True” correct=“True” description=“True, curly haired people find their hair becomes tight and unmanageable as bad weather approaches.” >
<Option Number=“B” title=“False” >
</Question>
- <Question number=“8” title=“Which of the following is NOT a valid weather predicting device:”>
<Option Number=“A” title=“A rainbow in the afternoon is a sign of good weather” >
<Option Number=“B” title=“A corona around the moon enlarges if fair weather lies ahead” >
<Option Number=“C” title=“Insect-eating birds fly lower when a storm is approaching” >
<Option Number=“D” title=“Unusual mammal activity at night often indicates coming rainfall” correct=“True” description=“Unusual mammal activity at night is NOT an indication of coming rainfall” >
</Question>
- <Question number=“9” title=“How long does it take for eyes to become adjusted to darkness?”>
<Option Number=“A” title=“5 - 10 minutes” >
<Option Number=“B” title=“15 - 25 minutes” >
<Option Number=“C” title=“30 - 40 minutes” correct=“True” description=“It takes 30 - 40 minutes for eyes to adjust to darkness” >
<Option Number=“D” title=“45 - 55 minutes” >
</Question>
- <Question number=“10” title=“When on the move, babies and small children should be:”>
<Option Number=“A” title=“Secured onto an adult’s back” >
<Option Number=“B” title=“Carried papoose style” correct=“True” description=“Babies and small children should be carried papoose style while on the move” >
<Option Number=“C” title=“Supported on an adult’s shoulders” >
<Option Number=“D” title=“Pushed in makeshift sleds” >
</Question>
- <Question number=“11” title=“River currents are the fastest:”>
<Option Number=“A” title=“On the inside of bends” >
<Option Number=“B” title=“On the outside of bends” correct=“True” description=“River currents are fatest on the outside of bends” >
<Option Number=“C” title=“Near waterfalls” >
<Option Number=“D” title=“Near the ocean” >
</Question>
- <Question number=“12” title=“Almost any signal repeated ____ times will serve as a distress signal.”>
<Option Number=“A” title=“3” >
<Option Number=“B” title=“5” >
<Option Number=“C” title=“6” correct=“True” description=“Signals repeated 6 times will serve as a distress signal” >
<Option Number=“D” title=“9” >
</Question>
</Topics>
Programmer XR | 4:18 AM May 23, 2011
Thanks for this explanation about SAX parsing, here is another tutorial about XML parsing in Android. But that one is based around converting the XML to a Document. Here is a link:
http://p-xr.com/android-tutorial-how-to-parseread-xml-data-into-android-listview/
lucki | 8:18 PM December 27, 2011
i’m new in android and i have to parse this xml data wht can i do for tht
<data>
- <galaries>
<galaryid>gly117L6xuN</galaryid>
<galaryName>first</galaryName>
<galarytype>Free</galarytype>
<galarydescription>free set of images</galarydescription>
<galaryCover>http://youmakethepage.com/wall/server/uploads/gly117L6xuN/7428s613kd92ab.jpg</galaryCover>
</galaries>
- <galaries>
<galaryid>gly462UcL8q</galaryid>
<galaryName>second</galaryName>
<galarytype>Paid</galarytype>
<galarydescription>paid gallary</galarydescription>
<galaryCover>http://youmakethepage.com/wall/server/uploads/gly462UcL8q/23549ja516jzuo9.jpg</galaryCover>
</galaries>
- <galaries>
<galaryid>gly346J4Gkr</galaryid>
<galaryName>third</galaryName>
<galarytype>Paid</galarytype>
<galarydescription>test</galarydescription>
<galaryCover>http://youmakethepage.com/wall/server/uploads/gly346J4Gkr/20500hz8fyqrqt1.jpg</galaryCover>
</galaries>
- <galaries>
<galaryid>gly2441Y4pu</galaryid>
<galaryName>forth</galaryName>
<galarytype>Paid</galarytype>
<galarydescription>description</galarydescription>
<galaryCover>http://youmakethepage.com/wall/server/uploads/gly2441Y4pu/33156v7euvudhpr.jpg</galaryCover>
</galaries>
- <galaries>
<galaryid>gly28OLNAI</galaryid>
<galaryName>fifth</galaryName>
<galarytype>Paid</galarytype>
<galarydescription>test</galarydescription>
<galaryCover>http://youmakethepage.com/wall/server/uploads/gly28OLNAI/3828175vee6crbj.jpg</galaryCover>
</galaries>
- <galaries>
<galaryid>gly581PORDL</galaryid>
<galaryName>sixth</galaryName>
<galarytype>Paid</galarytype>
<galarydescription>description</galarydescription>
<galaryCover>http://youmakethepage.com/wall/server/uploads/gly581PORDL/horses208.jpg</galaryCover>
</galaries>
</data>