1

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");
    }
    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:&quot;charlottetown&quot;">
    <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>
Maksym Gontar
  • 22,765
  • 10
  • 78
  • 114
starcaller
  • 979
  • 3
  • 16
  • 25
  • one more question, you xml seems to be formed incorrectly, since there are several fields with same name within one < object > tag (ex < field name="mods.subject" >Prince Edward Island< /field > < field name="mods.subject" >Description and travel< /field > ) is it correct behaviour (asking because it's like not normalized data model)? If yes, then (since we have to store these values, do you want them to be concatenated?) – Maksym Gontar Mar 19 '10 at 06:50
  • also, is it significant for you to have all fields sorted in same order as in xml? – Maksym Gontar Mar 19 '10 at 06:58
  • thanks so much MAX ,yea, this xml is kind of odd, but it is the xml file the server is using, and it will be very nice to have the values concatenated – starcaller Mar 19 '10 at 13:30
  • If the XML is standard have a look at JDOM: http://www.jdom.org/ – James P. Jan 14 '11 at 08:14

2 Answers2

1

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...

Maksym Gontar
  • 22,765
  • 10
  • 78
  • 114
  • but the get and set methods in the XMLObject class are never invoked – starcaller Mar 17 '10 at 00:07
  • You can use them to not mess around with field names string values – Maksym Gontar Mar 17 '10 at 06:34
  • the problem is after reading the XML file, it displayed nothing on the screen, and no exception was thrown. i tried to modify it, but there is still nothing coming up – starcaller Mar 17 '10 at 12:53
  • Are you talking about the sample I have provide? I have tested it with storm/bold/curve, it's working. However if you trying to get xml ove httpConnection, don't forget to run MDS simulator! Have you tried to debug it? Are XMLObjects filled? – Maksym Gontar Mar 17 '10 at 13:32
  • no i just saved the xml, do u have msn? maybe you can add me on msn, so we can talk much easier. thx mine is ionlylovenana@hotmail.com – starcaller Mar 17 '10 at 13:41
  • i used private static String xmlres = "res/xml1.xml"; to read the xml file and stored it as string and used ByteArrayInputStream bais = new ByteArrayInputStream(xmlres.getBytes()) to convert it to the inputstream – starcaller Mar 17 '10 at 13:47
  • see http://supportforums.blackberry.com/t5/Java-Development/Not-able-to-read-text-or-binary-file/m-p/307684;jsessionid=B409B9CE6C5F780DFF617C5D499ACC92#M54208 and check input stream next time so it will be easy to figure out issue. – Maksym Gontar Mar 17 '10 at 14:34
  • I don't mind to communicate but it's just the point of SO to help a wider range of coders having same issues so please keep it here on SO. – Maksym Gontar Mar 17 '10 at 14:37
  • i don't think it is the input stream issue since i specified the file name – starcaller Mar 17 '10 at 17:01
  • i tried to debug to see whether the file was correctly input, i used the toString() method to convert the inputstream to string and display but i only got java.io.ByteArrayInputStream@6610964, what does this mean? – starcaller Mar 17 '10 at 17:38
  • i am sure that the xml is now correctly inputed but it keeps having NullpointerException – starcaller Mar 17 '10 at 18:10
  • cant help with that without seeing code, can you edit your question and add your code? – Maksym Gontar Mar 17 '10 at 18:40
  • java.io.ByteArrayInputStream@6610964 in toString means its an object name and memory id and to get string value use IOUtilities.streamToBytes(in) – Maksym Gontar Mar 17 '10 at 18:43
  • Hi Changqui. It's working as it should. make sure you have put xml file into [project]/src/xml/ folder. And once again, have you tried the sample I have post? – Maksym Gontar Mar 18 '10 at 13:45
  • yea the sample you put works i think the problem is the xml i has to use, i posted the sample you can have a look at it. – starcaller Mar 18 '10 at 16:49
  • there is another tag named in it – starcaller Mar 18 '10 at 16:53
  • i just want to take text from it – starcaller Mar 18 '10 at 20:29
  • thanks so much MAX ,yea, this xml is kind of odd, but it is the xml file the server is using, and it will be very nice to have the values concatenated – starcaller Mar 19 '10 at 12:25
1
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

    }
}
sth
  • 222,467
  • 53
  • 283
  • 367