This code makes the incorrect assumption that the characters
method will be called only once between the startElement
and endElement
calls for a tag.
Instead of having the logic for setting the values in the characters
method, you need initialize a buffer in the startElement
method, collect characters into the buffer in the characters
method, and then make the assignments and clear the buffer in the endElement
method.
EDIT:
Actually, there were a few other issues in your code...
You had setMobilePhone and setWorkPhone in your model class setting the homePhone field... An inevitable risk when you copy-modify code.
And your handler was only creating one result, and would have overwritten and only returned the last one in the file.
I've played with it, changed some of the methods more to Java standard naming, and changed some of the xml to CamelCase as well.
Revised XML:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<PhoneBook>
<PhoneBookEntry>
<FirstName>John</FirstName>
<LastName>Connor</LastName>
<Address>5,Downing Street</Address>
<Phone loc="home">9875674567</Phone>
<Phone loc="work">9875674567</Phone>
<Phone loc="mobile">78654562341</Phone>
</PhoneBookEntry>
<PhoneBookEntry>
<FirstName>John</FirstName>
<LastName>Smith</LastName>
<Address>6,Downing Street</Address>
<Phone loc="home">678-56-home</Phone>
<Phone loc="work">678-59-work</Phone>
<Phone loc="mobile">678-85-mobile</Phone>
</PhoneBookEntry>
</PhoneBook>
Revised ParsedExampleDataSet:
public class ParsedExampleDataSet {
private String firstName = null;
private String lastName =null;
private String address =null;
private String homePhone =null;
private String workPhone =null;
private String mobilePhone =null;
//Firstname
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
//Lastname
public String getLastName(){
return lastName;
}
public void setLastName(String lastName){
this.lastName = lastName;
}
//address
public String getAddress(){
return address;
}
public void setAddress(String Address){
this.address =Address;
}
public void setHomePhone(String homePhone){
this.homePhone =homePhone;
}
public void setWorkPhone(String homePhone){
this.workPhone =homePhone;
}
public void setMobilePhone(String homePhone){
this.mobilePhone =homePhone;
}
public String toString(){
return "firstName: " + this.firstName + "
" + "lastName=: " + this.lastName + "
" + "address: " + this.address + "
" + "homePhone: " + this.homePhone + "
" + "workPhone: " + this.workPhone + "
" + "mobilePhone: " + this.mobilePhone;
}
}
And the handler that does the parsing:
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import java.util.ArrayList;
import java.util.List;
public class ExampleHandler extends DefaultHandler {
// ===========================================================
// Fields
// ===========================================================
private boolean in_homePhone = false;
private boolean in_workPhone = false;
private boolean in_mobilePhone = false;
private StringBuffer stringBuffer;
private List<ParsedExampleDataSet> myParsedExampleDataSets;
private ParsedExampleDataSet myParsedExampleDataSet;
// ===========================================================
// Methods
// ===========================================================
public List<ParsedExampleDataSet> getParsedData() {
return myParsedExampleDataSets;
}
@Override
public void startDocument() throws SAXException {
myParsedExampleDataSets = new ArrayList<ParsedExampleDataSet>();
stringBuffer = new StringBuffer();
}
@Override
public void endDocument() throws SAXException {
// Nothing to do
}
/**
* Gets be called on opening tags like:
* <tag>
* Can provide attribute(s), when xml was like:
* <tag attribute="attributeValue">
*/
@Override
public void startElement(String namespaceURI, String localName,
String qName, Attributes atts) throws SAXException {
if (qName.equals("PhoneBookEntry")) {
myParsedExampleDataSet = new ParsedExampleDataSet();
}
if (qName.equals("Phone")) {
String phoneLocation = atts.getValue("loc");
if (phoneLocation.equals("home")) {
this.in_homePhone = true;
} else if (phoneLocation.equals("work")) {
this.in_workPhone = true;
} else if (phoneLocation.equals("mobile")) {
this.in_mobilePhone = true;
}
}
}
/**
* Gets be called on closing tags like:
* </tag>
*/
@Override
public void endElement(String namespaceURI, String localName, String qName)
throws SAXException {
String result = stringBuffer.toString();
stringBuffer.setLength(0);
if (in_homePhone) {
myParsedExampleDataSet.setHomePhone(result);
in_homePhone = false;
}
else if (in_mobilePhone) {
myParsedExampleDataSet.setMobilePhone(result);
in_mobilePhone = false;
}
else if (in_workPhone) {
myParsedExampleDataSet.setWorkPhone(result);
in_workPhone = false;
}
else if (qName.equals("FirstName")) {
myParsedExampleDataSet.setFirstName(result);
}
else if (qName.equals("LastName")) {
myParsedExampleDataSet.setLastName(result);
}
else if (qName.equals("Address")) {
myParsedExampleDataSet.setAddress(result);
}
else if (qName.equals("PhoneBookEntry")) {
myParsedExampleDataSets.add(myParsedExampleDataSet);
}
}
/**
* Gets be called on the following structure:
* <tag>characters</tag>
*/
@Override
public void characters(char ch[], int start, int length) {
stringBuffer.append(new String(ch, start, length));
}
}
It puts some likely unwanted whitespace in the fields, but I suspect you can figure out how to trim that.
Calling it, you get a list rather than a single object, but other than dealing with that, your calling code shouldn't have to change too much. I didn't try to work with that, as I'm not doing any of this on android.