XML Parser: Android, Blackberry, J2ME

Hello Friends,

I am developing application in various mobile technologies. Usually in client/server application, application gets data through web services. In my development career I came across requirement to parse XML(web service) in various platform. So parser needs to create for each. Here I am going to represent some classes through which user can use single parser across Android, RIM BB and J2ME platform.

First, you need to add blow all three classes in your application.

1. XMLParser.java


package com.myapp.xmlparser;

/**
 * The main XML Parser class.
 */

import java.io.*;

import java.util.*;

public class XMLParser
{
  /**
   * The reader from which the stream is being read
   */

  private Reader inputReader;

  /**
   * The handler for XML Events.
   */

  private XMLEventListener eventHandler;

  /**
   * The root tag for the document.
   */

  private String rootTag = null;

  /**
   * Flag to say whether or not this stream is UTF-8 encoded.
   */

  private boolean isUTF8Encoded;

  /**
   * The buffer for incomming data.
   */

  private StringBuffer dataBuffer;

  /**
   * The input stream being read.
   */

  private InputStream is;

  /**
   * Flag to say whether or not all tags should be converted to lower case
   */
   
  private boolean convertTagsToLowerCase;
  
  /**
   * Constructor, Used to override default dispatcher.
   *
   * @param _eventHandler The event handle to dispatch events through.
   */

  public XMLParser( XMLEventListener _eventHandler )
  {
    eventHandler = _eventHandler;
    dataBuffer = new StringBuffer();
    convertTagsToLowerCase = true;
  }

  /**
   * Method to indicate if all tags should be converted to lower case
   *
   * @param doConversion Whether or not to convert all tag names to lower case.
   */
   
  public void convertAllTagNamesToLowerCase( boolean doConversion )
  {
    convertTagsToLowerCase = doConversion;
  }
  
  /**
   * Method to set the flag to state whether or not the input is UTF-8
   * encoded. For the UTF-8 decoding to work the parse method MUST be
   * called by passing it a java.io.DataInputStream object.
   *
   * @param flag True if UTF-8 decoding should be performed on the input
   *  stream, false if not.
   */

  public void setInputUTF8Encoded( boolean flag )
  {
    isUTF8Encoded = flag;
  }

  /**
   * Method to get the next character from the input stream.
   */

  public int getNextCharacter()
    throws IOException
  {
    int actualValue = -1;

    int inputValue = inputReader.read();
    if( inputValue == -1 )
      return -1;

    // Single character
    if( isUTF8Encoded == false )
    {
      actualValue = inputValue;
    }
    else
    {
      inputValue &= 0xff;
      if      ( (inputValue & 0x80) == 0 )
      {
        actualValue = inputValue;
      }
      else if ( (inputValue & 0xF8) == 0xF0 )
      {
        actualValue = (inputValue & 0x1f)<<6;

        int nextByte = inputReader.read() & 0xff;
        if( (nextByte & 0xC0) != 0x80 )
          throw new IOException( "Invalid UTF-8 format" );
        actualValue += (nextByte & 0x3F )<<6;

        nextByte = inputReader.read() & 0xff;
        if( (nextByte & 0xC0) != 0x80 )
          throw new IOException( "Invalid UTF-8 format" );
        actualValue += (nextByte & 0x3F )<<6;

        nextByte = inputReader.read() & 0xff;
        if( (nextByte & 0xC0) != 0x80 )
          throw new IOException( "Invalid UTF-8 format" );
        actualValue += (nextByte & 0x3F );
      }
      else if ( (inputValue & 0xF0) == 0xE0 )
      {
        actualValue = (inputValue & 0x1f)<<6;

        int nextByte = inputReader.read() & 0xff;
        if( (nextByte & 0xC0) != 0x80 )
          throw new IOException( "Invalid UTF-8 format" );
        actualValue += (nextByte & 0x3F )<<6;

        nextByte = inputReader.read() & 0xff;
        if( (nextByte & 0xC0) != 0x80 )
          throw new IOException( "Invalid UTF-8 format" );
        actualValue += (nextByte & 0x3F );
      }
      else if ( (inputValue & 0xE0) == 0xC0 )
      {
        actualValue = (inputValue & 0x1f)<<6;

        int nextByte = inputReader.read() & 0xff;
        if( (nextByte & 0xC0) != 0x80 )
          throw new IOException( "Invalid UTF-8 format" );
        actualValue += (nextByte & 0x3F );
      }
    }

    return actualValue;
  }

  /**
   * Method to read until an end condition.
   *
   * @param endChar The character to stop reading on
   * @return A string representation of the data read.
   */

  private String readUntilEnd( char endChar )
    throws IOException, EndOfXMLException
  {
    StringBuffer data = new StringBuffer();

    int nextChar = getNextCharacter();
    if( nextChar == -1 )
      throw new EndOfXMLException();
    while( nextChar != -1 && nextChar != endChar )
    {
      data.append( (char) nextChar );
      nextChar = getNextCharacter();
    }
    if( nextChar != '<' && nextChar != '>')
      data.append( (char) nextChar );

    String returnData = data.toString();
    return returnData;
  }

  /**
   * Method to determine if a character is a whitespace.
   *
   * @param c The character to check.
   * @return true if the character is a whitespace, false if not.
   */

  private boolean isWhitespace( char c )
  {
    if( c == ' '
    ||  c == '\t'
    ||  c == '\r'
    ||  c == '\n' )
      return true;

    return false;
  }

  /**
   * Method to handle the attributes in a tag
   *
   * @param data The section of the tag holding the attribute details
   */

  private Hashtable handleAttributes( String data )
  {
    Hashtable attributes = new Hashtable();

    int length = data.length();
    int i = 0;
    while( i < length )
    {
      StringBuffer nameBuffer = new StringBuffer();

      char thisChar = data.charAt(i);
      while( isWhitespace( thisChar ) && i < length )
      {
        i++;
        if( i == length )
          break;
        thisChar = data.charAt(i);
      }
      if( thisChar == '>' || i == length )
        break;

      while( thisChar != '=' )
      {
        nameBuffer.append(thisChar);

        i++;
        if( i == length )
          break;

        thisChar = data.charAt(i);
      }

      if( i == length )
        break;

      String name = nameBuffer.toString().trim();

      // See if first character is a character
      i++;
      thisChar = data.charAt(i);
      while( isWhitespace( thisChar ) && i < length)
      {
        i++;
        if( i == length )
          break;
        thisChar = data.charAt(i);
      }

      int breakOn = 0;
      if( thisChar == '\"' )
      {
        breakOn = 1;
      }
      else if (thisChar =='\'' )
      {
        breakOn = 2;
      }

      // Set up buffer for value parameter
      StringBuffer valueBuffer = new StringBuffer();
      if( breakOn == 0 )
      {
        valueBuffer.append( thisChar );
      }

      i++;
      while( i < length )
      {
        thisChar = data.charAt(i);
        i++;
        if      ( breakOn == 0 && isWhitespace( thisChar ) )
        {
          break;
        }
        else if ( breakOn == 1 && thisChar == '\"' )
        {
          break;
        }
        else if ( breakOn == 2 && thisChar == '\'' )
        {
          break;
        }
        valueBuffer.append( thisChar );
      }
      String value = valueBuffer.toString();
      attributes.put( name, value );
    }

    return attributes;
  }

  /**
   * Method to handle the reading and dispatch of tag data.
   */

  private void handleTag()
    throws IOException, EndOfXMLException
  {
    boolean startTag = true,
            emptyTag = false,
            hasMoreData = true;
    String tagName = null;
    Hashtable attributes = null;

    String data = readUntilEnd ( '>' );

    if( data.startsWith( "?") )
      return;

    int substringStart = 0,
        substringEnd = data.length();

    if( data.startsWith( "/" )  )
    {
      startTag = false;
      substringStart++;
    }

    if( data.endsWith( "/" ) )
    {
      emptyTag = true;
      substringEnd--;
    }

    data = data.substring( substringStart, substringEnd );
    int spaceIdx = 0;
    while( spaceIdx < data.length()
    &&     isWhitespace( data.charAt(spaceIdx) ) == false )
      spaceIdx++;

    tagName = data.substring(0,spaceIdx);
    if( convertTagsToLowerCase )
      tagName = tagName.toLowerCase();

    if( spaceIdx != data.length() )
    {
      data = data.substring( spaceIdx+1 );
      attributes = handleAttributes( data );
    }
    
    if( startTag )
    {
      if( rootTag == null )
        rootTag = tagName;
      eventHandler.tagStarted( tagName, attributes);
    }

    if( emptyTag || !startTag )
    {
      eventHandler.tagEnded( tagName );
      if( rootTag != null && tagName.equals( rootTag ) )
        throw new EndOfXMLException();
    }
  }

  /**
   * Method to handle the reading in and dispatching of events for plain text.
   */

  private void handlePlainText()
    throws IOException, EndOfXMLException
  {
    String data = readUntilEnd ( '<' );
    eventHandler.plaintextEncountered( data );
  }

  /**
   * Parse wrapper for InputStreams
   *
   * @param _inputReader The reader for the XML stream.
   */

  public void  parse ( InputStream _is )
    throws IOException
  {
    is = _is;
    InputStreamReader isr = new InputStreamReader( is );
    parse( isr );
 }



  /**
   * The main parsing loop.
   *
   * @param _inputReader The reader for the XML stream.
   */

   public void  parse ( byte[] _is )
    throws IOException
  {
//    b_is = _is;
    ByteArrayInputStream isr = new ByteArrayInputStream( _is );
    parse( isr );
 }public void  parse ( Reader _inputReader )
    throws IOException
  {
    inputReader = _inputReader;
    try
    {
      while( true )
      {
        handlePlainText();
        handleTag();
      }
    }
    catch( EndOfXMLException x )
    {
      // The EndOfXMLException is purely used to drop out of the
      // continuous loop.
    }
  }
}

2. XMLEventListener.java

package com.myapp.xmlparser;

/**
 * Interface for classes wishing to listen to events generated by the parser.
 */

import java.util.*;

public interface XMLEventListener
{
  /**
   * Method called when an tag start is encountered.
   *
   * @param name Tag name.
   * @param attributes The tags attributes.
   */

  public void tagStarted( String name, Hashtable attributes );

  /**
   * Method called when some plain text between two tags is encountered.
   *
   * @param text The plain text in question.
   */

  public void plaintextEncountered( String text );

  /**
   * The method called when a tag end is encountered.
   *
   * @param name The name of the tag that has just ended.
   */

  public void tagEnded( String name );
}

3. EndOfXMLException.java

package com.myapp.xmlparser;

/**
 * Exception thrown when the end of a XML stream is reached.
 */

public class EndOfXMLException extends Exception
{
}

Include above package files into your application.
Now let’s parse sample xml.
book.xml

<root>
     <Book>
         <BookId stream="Mobile">1</BookId>
         <BookName>Android</BookName>
     </Book>
</root>

Create POJO as per given XML.

Book.java

public class Book 
{
	public String BookId;
	public String BookName;
	public String Stream;
	
	public String getBookId() {
		return BookId;
	}
	public void setBookId(String bookId) {
		BookId = bookId;
	}
	public String getBookName() {
		return BookName;
	}
	public void setBookName(String bookName) {
		BookName = bookName;
	}
	public String getStream() {
		return Stream;
	}
	public void setStream(String stream) {
		Stream = stream;
	}	
}

Create Parser for book.xml
BookXML.java

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package com.myapp.parser;

import com.myapp.Book;
import com.myapp.xmlparser.XMLEventListener;
import com.myapp.xmlparser.XMLParser;


import java.util.Hashtable;
import java.util.Vector;

/**
 *
 * @author 
 */
public class BookXML implements XMLEventListener{

    public boolean BookId=false;
    public boolean BookName=false;
    public boolean Stream=false;
    Vector list;
    Book listElement;

    public BookXML()
    {
        list = new Vector();
    }

    public Vector getBookResponse()
    {
        return list;
    }

     public void Parse(byte[] xmldata) throws Exception
    {
        Parse(this, xmldata);
    }

    protected void Parse(XMLEventListener handler, byte[] xmldata) throws Exception {
        Parse(handler, true, xmldata);
    }

    protected void Parse(XMLEventListener handler, boolean shouldcache, byte[] xmldata) throws Exception{

            XMLParser parser = new XMLParser(this);
            parser.parse(xmldata);
    }

    public void tagStarted(String name, Hashtable attributes) {
    	
    	if(name.equalsIgnoreCase("Book"))        
    		listElement = new Book();
    	else
        if(name.equalsIgnoreCase("BookId"))
        {        	
        	listElement.setStream(attributes.get("stream").toString());
            BookId = true;
        }
        else
        if(name.equalsIgnoreCase("BookName"))
            BookName = true;        
    }


    public void plaintextEncountered(String text) {
        if(BookId)
            listElement.setBookId(text);
        if(BookName)
            listElement.setBookName(text);        
    }

    public void tagEnded(String name) {
        if(name.equalsIgnoreCase("Book"))                    
            list.addElement(listElement);        
        else
        if(name.equalsIgnoreCase("BookId"))
            BookId= false;
        else
        if(name.equalsIgnoreCase("BookName"))
            BookName = false;
    }

}

How to use in your activity class?
MainActivity.java

//This below xml might come from static resources or from by calling webservice.
String xmlToBeParse = "<root><Book><BookId stream="Mobile">1</BookId><BookName>Android</BookName></Book></root>";
BookXML xml = new BookXML();
try
{
     xml.Parse(xmlToBeParse.getBytes());
     Vector response = xml.getBookResponse();
     for(int i=0;i<response.size();i++)
     {
           Book book = response.elementAt(i);
           System.out.println("Book Id : "+ book.getBookId());
           System.out.println("Book Name : "+ book.getBookName());
           System.out.println("Book Stream : "+ book.getStream());
     }
}
catch(Exception e)
{         
      e.printStackTrace();
}

Hope these all may helpful to you… :)
Cheers!!

About these ads

One thought on “XML Parser: Android, Blackberry, J2ME

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s