I have a problem with using the SAX parser to parse a XML file. It is a complex XML file, it is like the following.
package com.ahoy.utils;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.Vector;
import net.rim.device.api.xml.parsers.ParserConfigurationException;
import net.rim.device.api.xml.parsers.SAXParser;
import net.rim.device.api.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import com.ahoy.bean.DealData;
public class XMLDealsParser extends DefaultHandler {
boolean currentElement = false;
String currentValue = null;
DealData currentDealData = null;
String previousNodeName = new String("nil");
public Vector dealVector = new Vector(5);
//public static Vector geoDataItems = null;
public XMLDealsParser(String data){
InputStream inputStream=null;
SAXParser sp;
try {
inputStream = new ByteArrayInputStream(data.getBytes());
SAXParserFactory spf = SAXParserFactory.newInstance();
sp = spf.newSAXParser();
sp.parse(inputStream, this);
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
Logger.error(" -------XMLDealsParser >> XMLDealsParser() ",e);
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
Logger.error(" -------XMLDealsParser >> XMLDealsParser() ",e);
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
Logger.error(" -------XMLDealsParser >> XMLDealsParser() ",e);
e.printStackTrace();
}
}
public Vector getDealList() {
return dealVector;
}
public void setDealList(Vector dealList) {
this.dealVector = dealList;
}
/** Called when tag starts ( ex:- <name>AndroidPeople</name>
* -- <name> )*/
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
currentElement = true;
if (localName.equals("deal"))
{
/** Start */
this.currentDealData = new DealData();
}if (localName.equals("id"))
{
/** Start */
}
}
/** Called when tag closing ( ex:- <name>AndroidPeople</name>
* -- </name> )*/
public void endElement(String uri, String localName, String qName)
throws SAXException {
currentElement = true;
/** set value */
if (localName.equalsIgnoreCase("deal"))
{
dealVector.addElement(currentDealData);
return;
}
if (localName.equalsIgnoreCase("id"))
{
currentDealData.id = currentValue;
}else if (localName.equalsIgnoreCase("score"))
{
currentDealData.score = currentValue;
}else if (localName.equalsIgnoreCase("shortDescription"))
{
currentDealData.shortDescription = currentValue;
}
//dealVector.addElement(currentGeoData);
System.out.println("dealVector.size():"+ dealVector.size());
}
/** Called to get tag characters ( ex:- <name>AndroidPeople</name>
* -- to get AndroidPeople Character ) */
public void characters(char[] ch, int start, int length)
throws SAXException {
if (currentElement) {
currentValue = new String(ch, start, length);
System.out.println("DATA: " + currentValue);
currentElement = false;
}
}
public void callback(String data) throws Exception {
// TODO Auto-generated method stub
}
}
UPDATE updated to skip span and concat values from fields with same name
Hi! I would suggest to use hashtable to handle those "fields":
class XMLObject {
private Hashtable mFields = new Hashtable();
private int mN = -1;
public int getN() {
return mN;
}
public void setN(int n) {
mN = n;
}
public boolean isFieldExist(String key)
{
return mFields.containsKey(key);
}
public String getStringField(String key) {
return (String) mFields.get(key);
}
public void setStringField(String key, String value) {
mFields.put(key, value);
}
public String getPID() {
return getStringField("PID");
}
public void setPID(String pid) {
setStringField("PID", pid);
}
public String getDcCoverage() {
return getStringField("dc.coverage");
}
public void setDcCoverage(String dcCoverage) {
setStringField("dc.coverage", dcCoverage);
}
public String getFgsOwnerId() {
return getStringField("fgs.ownerId");
}
public void setFgsOwnerId(String fgsOwnerId) {
setStringField("fgs.ownerId", fgsOwnerId);
}
public String dccreator() {
return getStringField("dc.creator");
}
public void dccreator(String dccreator) {
setStringField("dc.creator", dccreator);
}
public String getdcformat() {
return getStringField("dc.format");
}
public void setdcformat(String dcformat) {
setStringField("dc.format", dcformat);
}
public String getdcidentifier() {
return getStringField("dc.identifier");
}
public void setdcidentifier(String dcidentifier) {
setStringField("dc.identifier", dcidentifier);
}
public String getdclanguage() {
return getStringField("dc.language");
}
public void setdclanguage(String dclanguage) {
setStringField("dc.language", dclanguage);
}
public String getdcpublisher() {
return getStringField("dc.publisher");
}
public void setdcpublisher(String dcpublisher) {
setStringField("dc.publisher", dcpublisher);
}
public String getdcsubject() {
return getStringField("dc.subject");
}
public void setdcsubject(String dcsubject) {
setStringField("dc.subject", dcsubject);
}
public String getdctitle() {
return getStringField("dc.title");
}
public void setdctitle(String dctitle) {
setStringField("dc.title", dctitle);
}
public String getdctype() {
return getStringField("dc.type");
}
public void setdctype(String dctype) {
setStringField("dc.type", dctype);
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("N:" + mN + ";");
Enumeration keys = mFields.keys();
while (keys.hasMoreElements()) {
String key = (String) keys.nextElement();
sb.append(key + ":" + mFields.get(key) + ";\n");
}
return sb.toString();
}
}
Then in handler you will not have to set some specific class member, just put value using "name" attribute as a key:
class XMLObjectHandler extends DefaultHandler {
private String mCurrentTag = "";
private String mCurrentText = "";
private Attributes mCurrentAttr = null;
private XMLObject[] mXMLObjects = new XMLObject[] {};
private XMLObject mCurrentXMLObject = new XMLObject();
private boolean mIgnoreTag = false;
public XMLObject[] getXMLObjects() {
return mXMLObjects;
}
public void startElement(String uri, String localName, String name,
Attributes attributes) throws SAXException {
mIgnoreTag = mCurrentTag.equalsIgnoreCase("field")
&& name.equalsIgnoreCase("span");
if (!mIgnoreTag) {
mCurrentTag = name;
mCurrentAttr = attributes;
} else {
mCurrentText += " ";
}
if (mCurrentTag.equalsIgnoreCase("object")) {
mCurrentXMLObject = new XMLObject();
mCurrentXMLObject.setN(Integer
.parseInt(mCurrentAttr.getValue("no")));
}
}
public void characters(char[] ch, int start, int length)
throws SAXException {
if (mCurrentTag.equalsIgnoreCase("field"))
mCurrentText = mCurrentText.concat(new String(ch, start, length));
}
public void endElement(String uri, String localName, String name)
throws SAXException {
if (name.equalsIgnoreCase("field")) {
String fieldName = mCurrentAttr.getValue("name");
if(mCurrentXMLObject.isFieldExist(fieldName))
{
mCurrentText = mCurrentXMLObject.getStringField(fieldName)
+ " " + mCurrentText;
}
mCurrentXMLObject.setStringField(fieldName, mCurrentText);
} else if (name.equalsIgnoreCase("object")) {
Arrays.add(mXMLObjects, mCurrentXMLObject);
}
if (!mIgnoreTag) {
mCurrentTag = "";
mCurrentText = "";
} else {
mCurrentText += " ";
}
}
}
See sample usage:
public Scr() {
StringBuffer sb = new StringBuffer();
sb.append("<Objects>");
sb.append("<Object no=\"1\">");
sb
.append("<field name=\"PID\">ilives:87877</field>"+
"<field name=\"dc.coverage\">Charlottetown</field>"+
"<field name=\"fgs.ownerId\">fedoraAdmin</field>");
sb.append("</Object>");
sb.append("<Object no=\"2\">");
sb
.append("<field name=\"PID\">ilives:87878</field>"+
"<field name=\"dc.coverage\">Rimston</field>"+
"<field name=\"fgs.ownerId\">jamesAdmin</field>");
sb.append("</Object>");
sb.append("</Objects>");
String xml = sb.toString();
ByteArrayInputStream bais =
new ByteArrayInputStream(xml.getBytes());
XMLObject[] xmlObjects = getXMLObjects(bais);
for (int i = 0; i < xmlObjects.length; i++) {
XMLObject o = xmlObjects[i];
add(new LabelField(o.toString()));
}
}
static XMLObject[] getXMLObjects(InputStream is) {
XMLObjectHandler xmlObjectHandler = new XMLObjectHandler();
try {
SAXParser parser = SAXParserFactory.newInstance()
.newSAXParser();
parser.parse(is, xmlObjectHandler);
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return xmlObjectHandler.getXMLObjects();
}
}
alt text http://img441.imageshack.us/img441/1372/saxj.jpg
PS If there will be performance issues (say having over 1000 xml objects) just replace hashtable with class members and update handler accordingly...