BlackBerry/J2ME - SAX parse collection of objects with attributes
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.
<Objects>
<Object no="1">
<field name="PID">ilives:87877</field>
<field name="dc.coverage">Charlottetown</field>
<field name="fgs.ownerId">fedoraAdmin</field>
</Object>
<Object no="2">......
I am confused how to get the names in each field, and how to store the information of each object.
import java.util.Enumeration;
import java.util.Hashtable;
public class XMLObject {
private Hashtable mFields = new Hashtable();
private int mN = -1;
public int getN() {
return mN;
}
public void setN(int n) {
mN = n;
}
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");
}
开发者_如何学Python 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)+";");
}
return sb.toString();
}
}
i used the same handler class you provided
import java.io.*;
import net.rim.device.api.system.Bitmap;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.InputStream;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.*;
import org.xml.sax.helpers.DefaultHandler;
public class xmlparsermainscreen extends MainScreen{
private static String xmlres = "/xml/xml1.xml";
private RichTextField textOutputField;
public xmlparsermainscreen() throws ParserConfigurationException,
net.rim.device.api.xml.parsers.ParserConfigurationException,
IOException
{
InputStream inputStream = getClass().getResourceAsStream(xmlres);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[10000];
int bytesRead = inputStream.read(buffer);
while (bytesRead > 0) {
baos.write(buffer, 0, bytesRead);
bytesRead = inputStream.read(buffer);
}
baos.close();
String result=baos.toString();
ByteArrayInputStream bais =
new ByteArrayInputStream(result.getBytes());
XMLObject[] xmlObjects = getXMLObjects(bais);
for (int i = 0; i < xmlObjects.length; i++) {
XMLObject o = xmlObjects[i];
textOutputField = new RichTextField();
add(textOutputField);
textOutputField.setText(o.toString());
// add(new LabelField(o.toString()));
}
LabelField resultdis=new LabelField("resultdisplay");
add(resultdis);
//textOutputField = new RichTextField();
//add(textOutputField);
//textOutputField.setText(result);
}
static XMLObject[] getXMLObjects(InputStream is) throws
ParserConfigurationException {
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();
}
}
App code:
import java.io.IOException;
import javax.xml.parsers.ParserConfigurationException;
import net.rim.device.api.ui.UiApplication;
public class xmlparser extends UiApplication {
private xmlparser() throws ParserConfigurationException,
net.rim.device.api.xml.parsers.ParserConfigurationException,
IOException
{
pushScreen( new xmlparsermainscreen() );
}
public static void main( String[] args )
throws ParserConfigurationException,
net.rim.device.api.xml.parsers.ParserConfigurationException,
IOException
{
new xmlparser().enterEventDispatcher();
}
}
the xml i am using
<resultPage xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:foxml="info:fedora/fedora-system:def/foxml#"
xmlns:zs="http://www.loc.gov/zing/srw/" indexName="BasicIndex"
dateTime="Wed Mar 17 09:13:26 ADT 2010">
<gfindObjects hitTotal="199" resultPageXslt="" hitPageSize="2"
hitPageStart="1" query="dc.title:"charlottetown"">
<objects>
<object no="1" score="4.550192">
<field name="PID">ilives:86472</field>
<field name="dc.coverage">Charlottetown (P.E.I.)</field>
<field name="dc.coverage">Prince Edward Island</field>
<field name="dc.creator">Hines, Sherman , 1941-</field>
<field name="dc.format">electronic</field>
<field name="dc.identifier">None</field>
<field name="dc.identifier">ilives:86472</field>
<field name="dc.language">eng</field>
<field name="dc.publisher">Random House</field>
<field name="dc.subject">Description--Views</field>
<field name="dc.subject">Description and
travel--Views</field>
<field name="dc.title" snippet="yes">
<span class="highlight">Charlottetown</span>and Prince
Edward Island: Sherman Hines images of Canada</field>
<field name="dc.type">collection</field>
<field name="dc.type">bib-only</field>
<field name="fgs.createdDate">
2009-06-09T18:24:11.972Z</field>
<field name="fgs.label">191_86472 _foXML.xml</field>
<field name="fgs.lastModifiedDate">
2009-06-23T19:29:44.930Z</field>
<field name="fgs.ownerId">fedoraAdmin</field>
<field name="fgs.state">Active</field>
<field name="mods.dateIssued">1990</field>
<field name="mods.extent">1 v. unpaged ; 22 cm.</field>
<field name="mods.form">print</field>
<field name="mods.issuance">monographic</field>
<field name="mods.place_of_publication">Toronto</field>
<field name="mods.publisher">Random House</field>
<field name="mods.subTitle">Sherman Hines images of
Canada</field>
<field name="mods.subject">Charlottetown (P.E.I.)</field>
<field name="mods.subject">Description</field>
<field name="mods.subject">Views</field>
<field name="mods.subject">Prince Edward Island</field>
<field name="mods.subject">Description and travel</field>
<field name="mods.subject">Views</field>
<field name="mods.title">Charlottetown and Prince Edward
Island</field>
<field name="rels.hasModel">
info:fedora/ilives:bookCModel</field>
<field name="rels.isMemberOf">
info:fedora/ilives:collection</field>
</object>
</objects>
</gfindObjects>
</resultPage>
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...
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
}
}
精彩评论