Sunday, July 3, 2011

Parsing XML wit SAX parser

Android provides org.xml.sax package that has that provides the event-driven SAX parser.
to parse the previous response with SAX parser, we have to create a class extending DefaultHandler and override the following methods:
  1. startDocument(): invoked when the xml document is open, there we can initialize any member variables.
  2. startElement(String uri, String localName, String qName, Attributes attributes): invoked when the parser encounters a xml node, here we can initialize specific instances of our person object.
  3. endElement(String uri, String localName, String Name): invoked when the parser reaches the closing of a xml tag. here the element value would have been completely read.
  4. characters(char[] ch, int start, int length): this method is called when the parser reads characters of a node value.
we want to parse this xml response:
<?xml version="1.0"?>
<person>
<firstname>Jack</firstname>
<lastname>smith</lastname>
<age>28</age>
</person>
so our parsing class will be like this:
/**
* SAX parser to parse persons response
*/
public class PersonParser extends DefaultHandler
{

// arraylist to store person objects
ArrayList persons;
// temporary person object
Person tempPerson;
// string builder acts as a buffer
StringBuilder builder;

/**
* Initialize the arraylist
* @throws SAXException
*/
@Override
public void startDocument() throws SAXException {
pesons=new ArrayList();

}

/**
* Initialize the temp person object which will hold the parsed in//fo
* and the string builder that will store the read characters
* @param uri
* @param localName
* @param qName
* @param attributes
* @throws SAXException
*/
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {

if(localName.equalsIgnoreCase.equals("person")){
tempPerson=new Person();
builder=new StringBuilder();
}

}
/**
* Finished reading the person tag, add it to arraylist
* @param uri
* @param localName
* @param qName
* @throws SAXException
*/
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
// finished reading a person, add it to the arraylist
if(localName.toLowerCase().equals("person"))
{
this.persons.add(tempPerson);
}
// finished reading "firstname" tag assign it to the temp person
else if(localName.toLowerCase().equals("firstname")){
tempPerson.firstName=builder.toString();
}
// finished reading "lastname" tag assign it to the temp person
else if(localName.toLowerCase().equals("lastname")){
tempPerson.lastName=builder.toString();
}
// finished reading "age" tag assign it to the temp person
else if(localName.toLowerCase().equals("age")){
tempPerson.age=Integer.parseInt(builder.toString());
}
}

/**
* Read the value of each tag
* @param ch
* @param start
* @param length
* @throws SAXException
*/
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
// read the characters and append them to the buffer
String tempString=new String(ch, start, length);
builder.append(tempString);
}
}
the code is pretty easy, the parser iterates over each node, you check the current node name and take an action.

then we call the parser like this:
public ArrayList getPersons(final String response) throws ParserConfigurationException, SAXException, IOException
{
BufferedReader br=new BufferedReader(new StringReader(response));
InputSource is=new InputSource(br);
PersonParser parser=new PersonParser();
SAXParserFactory factory=SAXParserFactory.newInstance();
SAXParser sp=factory.newSAXParser();
XMLReader reader=sp.getXMLReader();
reader.setContentHandler(parser);
reader.parse(is);
ArrayList persons=parser.persons;

return persons;

}

No comments:

Post a Comment