views:

1166

answers:

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>
A: 

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

PS If there will be performance issues (say having over 1000 xml objects) just replace hashtable with class members and update handler accordingly...

Max Gontar
but the get and set methods in the XMLObject class are never invoked
starcaller
You can use them to not mess around with field names string values
Max Gontar
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
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?
Max Gontar
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 [email protected]
starcaller
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
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.
Max Gontar
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.
Max Gontar
i don't think it is the input stream issue since i specified the file name
starcaller
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
i am sure that the xml is now correctly inputed but it keeps having NullpointerException
starcaller
cant help with that without seeing code, can you edit your question and add your code?
Max Gontar
java.io.ByteArrayInputStream@6610964 in toString means its an object name and memory id and to get string value use IOUtilities.streamToBytes(in)
Max Gontar
hi MAX i have posted my code please take a look at it thanks
starcaller
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?
Max Gontar
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
there is another tag named <span> in it
starcaller
ok, so you want to keep this span or just take text from it?
Max Gontar
i just want to take text from it
starcaller
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