Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
662 views
in Technique[技术] by (71.8m points)

xml - Android: Sax parsing returns null values and retrieve values in tags of same name

I have these XML on a URL

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

I was able to extract the values on firstname, lastname and Address, but when it comes to Phone tags, my code returns null values. Here are my code:

ParsingXML.java

package com.example.parsingxml;

import java.net.Proxy;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.URL;
import java.net.URLConnection;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
public class ParsingXML extends Activity {



    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
         //System.setProperty("http.proxyHost"," 129.188.69.100 "); 
         //System.setProperty("http.proxyPort","1080");
         //System.setProperty("http.nonProxyHosts","10.228.97.76");

         /* Create a new TextView to display the parsingresult later. */
         TextView tv = new TextView(this);
         try {
              /* Create a URL we want to load some xml-data from. */
              URL url = new URL("http://somedomain.com/jm/sampleXML.xml");
                           URLConnection ucon = url.openConnection();
              /* Get a SAXParser from the SAXPArserFactory. */
              SAXParserFactory spf = SAXParserFactory.newInstance();
              SAXParser sp = spf.newSAXParser();

              /* Get the XMLReader of the SAXParser we created. */
              XMLReader xr = sp.getXMLReader();
              /* Create a new ContentHandler and apply it to the XML-Reader*/
              ExampleHandler myExampleHandler = new ExampleHandler();
              xr.setContentHandler(myExampleHandler);

              /* Parse the xml-data from our URL. */
              xr.parse(new InputSource(url.openStream()));
              /* Parsing has finished. */

              /* Our ExampleHandler now provides the parsed data to us. */
              ParsedExampleDataSet parsedExampleDataSet =
                                            myExampleHandler.getParsedData();

              /* Set the result to be displayed in our GUI. */
              tv.setText(parsedExampleDataSet.toString());

         } catch (Exception e) {
              /* Display any Error to the GUI. */
              tv.setText("Error: " + e.getMessage());

         }
         /* Display the TextView. */
         this.setContentView(tv);
    }
}

ExampleHandler.java

package com.example.parsingxml;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;


public class ExampleHandler extends DefaultHandler{

     // ===========================================================
     // Fields
     // ===========================================================

     private boolean in_outertag = false;
     private boolean in_innertag = false;
     private boolean in_firstname = false;
     private boolean in_lastname= false;
     private boolean in_Address=false;
     private boolean in_Phone=false;
     private boolean in_homePhone=false;
     private boolean in_workPhone=false;
     private boolean in_mobilePhone=false;


     private ParsedExampleDataSet myParsedExampleDataSet = new ParsedExampleDataSet();

     // ===========================================================
     // Getter & Setter
     // ===========================================================

     public ParsedExampleDataSet getParsedData() {
          return this.myParsedExampleDataSet;
     }

     // ===========================================================
     // Methods
     // ===========================================================
     @Override
     public void startDocument() throws SAXException {
          this.myParsedExampleDataSet = new ParsedExampleDataSet();
     }

     @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 (localName.equals("PhoneBook")) {
               this.in_outertag = true;
          }else if (localName.equals("PhonebookEntry")) {
               this.in_innertag = true;
          }else if (localName.equals("firstname")) {
               this.in_firstname = true;
          }else if (localName.equals("lastname"))  {
              this.in_lastname= true;
          }else if(localName.equals("Address"))  {
              this.in_Address= true;
          }else if (localName.equals("Phone")){
              this.in_Phone=true;
              String phoneattr=atts.getValue("loc");
              if(phoneattr.equals("home")){
                this.in_homePhone=true;
              }else if(phoneattr.equals("work")){
                this.in_workPhone=true;
              }else if(phoneattr.equals("mobile")){
                this.in_mobilePhone=true;
             }
        }  


          }

              //else if (localName.equals("tagwithnumber")) {
         // }
               // Extract an Attribute
              // String attrValue = atts.getValue("thenumber");
              // int i = Integer.parseInt(attrValue);
              // myParsedExampleDataSet.setExtractedInt(i);
        //  }


     /** Gets be called on closing tags like:
      * </tag> */
     @Override
     public void endElement(String namespaceURI, String localName, String qName)
               throws SAXException {
          if (localName.equals("Phonebook")) {
               this.in_outertag = false;
          }else if (localName.equals("PhonebookEntry")) {
               this.in_innertag = false;
          }else if (localName.equals("firstname")) {
               this.in_firstname = false;
          }else if (localName.equals("lastname"))  {
              this.in_lastname= false;
          }else if(localName.equals("Address"))  {
              this.in_Address= false;
          }else if(localName.equals("Phone"))   {
              this.in_Phone=false;
          }
     }

     /** Gets be called on the following structure:
      * <tag>characters</tag> */
     @Override
    public void characters(char ch[], int start, int length) {
          if(this.in_firstname){
          myParsedExampleDataSet.setfirstname(new String(ch, start, length));
          }
          if(this.in_lastname){
          myParsedExampleDataSet.setlastname(new String(ch, start, length));
          }
          if(this.in_Address){
              myParsedExampleDataSet.setAddress(new String(ch, start, length));
          }
          if(this.in_homePhone){
              myParsedExampleDataSet.sethomePhone(new String(ch, start, length));
          }
          if(this.in_workPhone){
              myParsedExampleDataSet.setworkPhone(new String(ch, start, length));
          }
          if(this.in_mobilePhone){
              myParsedExampleDataSet.setmobilePhone(new String(ch, start, length));
          }
    }
}

ParsedExampleDataSet.java

package com.example.parsingxml;

public class ParsedExampleDataSet {
    private String firstname = null;
    private String lastname=null;
    private String Address=null;
    private String Phone=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;
    }

    //Phone
    public String getPhone(){
        return Phone;
    }
    public void sethomePhone(String homePhone){
        this.homephone=homePhone;
    }
    public void setworkPhone(String homePhone){
        this.homephone=homePhone;
    }
    public void setmobilePhone(String homePhone){
        this.homephone=homePhone;
    }


    public String toString(){
         return "firstname: " + this.firstname + "
" + "lastname=: " + this.lastname + "
" + "Address: " + this.Address+ "
"  + "homephone: " + this.homephone + "
" + "workphone: " + this.workphone + "
" + "mobilephone: " + this.mobilephone;

    }
}

Another thing how can I retrieve both values in PhonebookEntry tags?

I'm kinda new to java and android dev, many thanks in advance! :)

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...