Package com.persiste.sdk.json.parser

Source Code of com.persiste.sdk.json.parser.JSONParser

/*
* $Id: JSONParser.java,v 1.1 2006/04/15 14:10:48 platform Exp $
* Created on 2006-4-15
*/
package com.persiste.sdk.json.parser;

import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import com.persiste.sdk.json.JSONArray;
import com.persiste.sdk.json.JSONObject;



/**
* Parser for JSON text. Please note that JSONParser is NOT thread-safe.
*
* @author FangYidong<fangyidong@yahoo.com.cn>
*/
public class JSONParser {
  public static final int S_INIT=0;
  public static final int S_IN_FINISHED_VALUE=1;//string,number,boolean,null,object,array
  public static final int S_IN_OBJECT=2;
  public static final int S_IN_ARRAY=3;
  public static final int S_PASSED_PAIR_KEY=4;
  public static final int S_IN_PAIR_VALUE=5;
  public static final int S_END=6;
  public static final int S_IN_ERROR=-1;
 
  private LinkedList handlerStatusStack;
  private Yylex lexer = new Yylex((Reader)null);
  private Yytoken token = null;
  private int status = S_INIT;
 
  private int peekStatus(LinkedList statusStack){
    if(statusStack.size()==0)
      return -1;
    Integer status=(Integer)statusStack.getFirst();
    return status.intValue();
  }
 
    /**
     *  Reset the parser to the initial state without resetting the underlying reader.
     *
     */
    public void reset(){
        token = null;
        status = S_INIT;
        handlerStatusStack = null;
    }
   
    /**
     * Reset the parser to the initial state with a new character reader.
     *
     * @param in - The new character reader.
     * @throws IOException
     * @throws ParseException
     */
  public void reset(Reader in){
    lexer.yyreset(in);
    reset();
  }
 
  /**
   * @return The position of the beginning of the current token.
   */
  public int getPosition(){
    return lexer.getPosition();
  }
 
  public Object parse(String s) throws ParseException{
    return parse(s, (ContainerFactory)null);
  }
 
  public Object parse(String s, ContainerFactory containerFactory) throws ParseException{
    StringReader in=new StringReader(s);
    try{
      return parse(in, containerFactory);
    }
    catch(IOException ie){
      /*
       * Actually it will never happen.
       */
      throw new ParseException(-1, ParseException.ERROR_UNEXPECTED_EXCEPTION, ie);
    }
  }
 
  public Object parse(Reader in) throws IOException, ParseException{
    return parse(in, (ContainerFactory)null);
  }
 
  /**
   * Parse JSON text into java object from the input source.
   *  
   * @param in
     * @param containerFactory - Use this factory to createyour own JSON object and JSON array containers.
   * @return Instance of the following:
   *  org.json.simple.JSONObject,
   *   org.json.simple.JSONArray,
   *   java.lang.String,
   *   java.lang.Number,
   *   java.lang.Boolean,
   *   null
   *
   * @throws IOException
   * @throws ParseException
   */
  public Object parse(Reader in, ContainerFactory containerFactory) throws IOException, ParseException{
    reset(in);
    LinkedList statusStack = new LinkedList();
    LinkedList valueStack = new LinkedList();
   
    try{
      do{
        nextToken();
        switch(status){
        case S_INIT:
          switch(token.type){
          case Yytoken.TYPE_VALUE:
            status=S_IN_FINISHED_VALUE;
            statusStack.addFirst(new Integer(status));
            valueStack.addFirst(token.value);
            break;
          case Yytoken.TYPE_LEFT_BRACE:
            status=S_IN_OBJECT;
            statusStack.addFirst(new Integer(status));
            valueStack.addFirst(createObjectContainer(containerFactory));
            break;
          case Yytoken.TYPE_LEFT_SQUARE:
            status=S_IN_ARRAY;
            statusStack.addFirst(new Integer(status));
            valueStack.addFirst(createArrayContainer(containerFactory));
            break;
          default:
            status=S_IN_ERROR;
          }//inner switch
          break;
         
        case S_IN_FINISHED_VALUE:
          if(token.type==Yytoken.TYPE_EOF)
            return valueStack.removeFirst();
          else
            throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
         
        case S_IN_OBJECT:
          switch(token.type){
          case Yytoken.TYPE_COMMA:
            break;
          case Yytoken.TYPE_VALUE:
            if(token.value instanceof String){
              String key=(String)token.value;
              valueStack.addFirst(key);
              status=S_PASSED_PAIR_KEY;
              statusStack.addFirst(new Integer(status));
            }
            else{
              status=S_IN_ERROR;
            }
            break;
          case Yytoken.TYPE_RIGHT_BRACE:
            if(valueStack.size()>1){
              statusStack.removeFirst();
              valueStack.removeFirst();
              status=peekStatus(statusStack);
            }
            else{
              status=S_IN_FINISHED_VALUE;
            }
            break;
          default:
            status=S_IN_ERROR;
            break;
          }//inner switch
          break;
         
        case S_PASSED_PAIR_KEY:
          switch(token.type){
          case Yytoken.TYPE_COLON:
            break;
          case Yytoken.TYPE_VALUE:
            statusStack.removeFirst();
            String key=(String)valueStack.removeFirst();
            Map parent=(Map)valueStack.getFirst();
            parent.put(key,token.value);
            status=peekStatus(statusStack);
            break;
          case Yytoken.TYPE_LEFT_SQUARE:
            statusStack.removeFirst();
            key=(String)valueStack.removeFirst();
            parent=(Map)valueStack.getFirst();
            List newArray=createArrayContainer(containerFactory);
            parent.put(key,newArray);
            status=S_IN_ARRAY;
            statusStack.addFirst(new Integer(status));
            valueStack.addFirst(newArray);
            break;
          case Yytoken.TYPE_LEFT_BRACE:
            statusStack.removeFirst();
            key=(String)valueStack.removeFirst();
            parent=(Map)valueStack.getFirst();
            Map newObject=createObjectContainer(containerFactory);
            parent.put(key,newObject);
            status=S_IN_OBJECT;
            statusStack.addFirst(new Integer(status));
            valueStack.addFirst(newObject);
            break;
          default:
            status=S_IN_ERROR;
          }
          break;
         
        case S_IN_ARRAY:
          switch(token.type){
          case Yytoken.TYPE_COMMA:
            break;
          case Yytoken.TYPE_VALUE:
            List val=(List)valueStack.getFirst();
            val.add(token.value);
            break;
          case Yytoken.TYPE_RIGHT_SQUARE:
            if(valueStack.size()>1){
              statusStack.removeFirst();
              valueStack.removeFirst();
              status=peekStatus(statusStack);
            }
            else{
              status=S_IN_FINISHED_VALUE;
            }
            break;
          case Yytoken.TYPE_LEFT_BRACE:
            val=(List)valueStack.getFirst();
            Map newObject=createObjectContainer(containerFactory);
            val.add(newObject);
            status=S_IN_OBJECT;
            statusStack.addFirst(new Integer(status));
            valueStack.addFirst(newObject);
            break;
          case Yytoken.TYPE_LEFT_SQUARE:
            val=(List)valueStack.getFirst();
            List newArray=createArrayContainer(containerFactory);
            val.add(newArray);
            status=S_IN_ARRAY;
            statusStack.addFirst(new Integer(status));
            valueStack.addFirst(newArray);
            break;
          default:
            status=S_IN_ERROR;
          }//inner switch
          break;
        case S_IN_ERROR:
          throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
        }//switch
        if(status==S_IN_ERROR){
          throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
        }
      }while(token.type!=Yytoken.TYPE_EOF);
    }
    catch(IOException ie){
      throw ie;
    }
   
    throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
  }
 
  private void nextToken() throws ParseException, IOException{
    token = lexer.yylex();
    if(token == null)
      token = new Yytoken(Yytoken.TYPE_EOF, null);
  }
 
  private Map createObjectContainer(ContainerFactory containerFactory){
    if(containerFactory == null)
      return new JSONObject();
    Map m = containerFactory.createObjectContainer();
   
    if(m == null)
      return new JSONObject();
    return m;
  }
 
  private List createArrayContainer(ContainerFactory containerFactory){
    if(containerFactory == null)
      return new JSONArray();
    List l = containerFactory.creatArrayContainer();
   
    if(l == null)
      return new JSONArray();
    return l;
  }
 
  public void parse(String s, ContentHandler contentHandler) throws ParseException{
    parse(s, contentHandler, false);
  }
 
  public void parse(String s, ContentHandler contentHandler, boolean isResume) throws ParseException{
    StringReader in=new StringReader(s);
    try{
      parse(in, contentHandler, isResume);
    }
    catch(IOException ie){
      /*
       * Actually it will never happen.
       */
      throw new ParseException(-1, ParseException.ERROR_UNEXPECTED_EXCEPTION, ie);
    }
  }
 
  public void parse(Reader in, ContentHandler contentHandler) throws IOException, ParseException{
    parse(in, contentHandler, false);
  }
 
  /**
   * Stream processing of JSON text.
   *
   * @see ContentHandler
   *
   * @param in
   * @param contentHandler
   * @param isResume - Indicates if it continues previous parsing operation.
     *                   If set to true, resume parsing the old stream, and parameter 'in' will be ignored.
   *                   If this method is called for the first time in this instance, isResume will be ignored.
   *
   * @throws IOException
   * @throws ParseException
   */
  public void parse(Reader in, ContentHandler contentHandler, boolean isResume) throws IOException, ParseException{
    if(!isResume){
      reset(in);
      handlerStatusStack = new LinkedList();
    }
    else{
      if(handlerStatusStack == null){
        isResume = false;
        reset(in);
        handlerStatusStack = new LinkedList();
      }
    }
   
    LinkedList statusStack = handlerStatusStack; 
   
    try{
      do{
        switch(status){
        case S_INIT:
          contentHandler.startJSON();
          nextToken();
          switch(token.type){
          case Yytoken.TYPE_VALUE:
            status=S_IN_FINISHED_VALUE;
            statusStack.addFirst(new Integer(status));
            if(!contentHandler.primitive(token.value))
              return;
            break;
          case Yytoken.TYPE_LEFT_BRACE:
            status=S_IN_OBJECT;
            statusStack.addFirst(new Integer(status));
            if(!contentHandler.startObject())
              return;
            break;
          case Yytoken.TYPE_LEFT_SQUARE:
            status=S_IN_ARRAY;
            statusStack.addFirst(new Integer(status));
            if(!contentHandler.startArray())
              return;
            break;
          default:
            status=S_IN_ERROR;
          }//inner switch
          break;
         
        case S_IN_FINISHED_VALUE:
          nextToken();
          if(token.type==Yytoken.TYPE_EOF){
            contentHandler.endJSON();
            status = S_END;
            return;
          }
          else{
            status = S_IN_ERROR;
            throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
          }
     
        case S_IN_OBJECT:
          nextToken();
          switch(token.type){
          case Yytoken.TYPE_COMMA:
            break;
          case Yytoken.TYPE_VALUE:
            if(token.value instanceof String){
              String key=(String)token.value;
              status=S_PASSED_PAIR_KEY;
              statusStack.addFirst(new Integer(status));
              if(!contentHandler.startObjectEntry(key))
                return;
            }
            else{
              status=S_IN_ERROR;
            }
            break;
          case Yytoken.TYPE_RIGHT_BRACE:
            if(statusStack.size()>1){
              statusStack.removeFirst();
              status=peekStatus(statusStack);
            }
            else{
              status=S_IN_FINISHED_VALUE;
            }
            if(!contentHandler.endObject())
              return;
            break;
          default:
            status=S_IN_ERROR;
            break;
          }//inner switch
          break;
         
        case S_PASSED_PAIR_KEY:
          nextToken();
          switch(token.type){
          case Yytoken.TYPE_COLON:
            break;
          case Yytoken.TYPE_VALUE:
            statusStack.removeFirst();
            status=peekStatus(statusStack);
            if(!contentHandler.primitive(token.value))
              return;
            if(!contentHandler.endObjectEntry())
              return;
            break;
          case Yytoken.TYPE_LEFT_SQUARE:
            statusStack.removeFirst();
            statusStack.addFirst(new Integer(S_IN_PAIR_VALUE));
            status=S_IN_ARRAY;
            statusStack.addFirst(new Integer(status));
            if(!contentHandler.startArray())
              return;
            break;
          case Yytoken.TYPE_LEFT_BRACE:
            statusStack.removeFirst();
            statusStack.addFirst(new Integer(S_IN_PAIR_VALUE));
            status=S_IN_OBJECT;
            statusStack.addFirst(new Integer(status));
            if(!contentHandler.startObject())
              return;
            break;
          default:
            status=S_IN_ERROR;
          }
          break;
       
        case S_IN_PAIR_VALUE:
          /*
           * S_IN_PAIR_VALUE is just a marker to indicate the end of an object entry, it doesn't proccess any token,
           * therefore delay consuming token until next round.
           */
          statusStack.removeFirst();
          status = peekStatus(statusStack);
          if(!contentHandler.endObjectEntry())
            return;
          break;
         
        case S_IN_ARRAY:
          nextToken();
          switch(token.type){
          case Yytoken.TYPE_COMMA:
            break;
          case Yytoken.TYPE_VALUE:
            if(!contentHandler.primitive(token.value))
              return;
            break;
          case Yytoken.TYPE_RIGHT_SQUARE:
            if(statusStack.size()>1){
              statusStack.removeFirst();
              status=peekStatus(statusStack);
            }
            else{
              status=S_IN_FINISHED_VALUE;
            }
            if(!contentHandler.endArray())
              return;
            break;
          case Yytoken.TYPE_LEFT_BRACE:
            status=S_IN_OBJECT;
            statusStack.addFirst(new Integer(status));
            if(!contentHandler.startObject())
              return;
            break;
          case Yytoken.TYPE_LEFT_SQUARE:
            status=S_IN_ARRAY;
            statusStack.addFirst(new Integer(status));
            if(!contentHandler.startArray())
              return;
            break;
          default:
            status=S_IN_ERROR;
          }//inner switch
          break;
         
        case S_END:
          return;
         
        case S_IN_ERROR:
          throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
        }//switch
        if(status==S_IN_ERROR){
          throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
        }
      }while(token.type!=Yytoken.TYPE_EOF);
    }
    catch(IOException ie){
      status = S_IN_ERROR;
      throw ie;
    }
    catch(ParseException pe){
      status = S_IN_ERROR;
      throw pe;
    }
    catch(RuntimeException re){
      status = S_IN_ERROR;
      throw re;
    }
    catch(Error e){
      status = S_IN_ERROR;
      throw e;
    }
   
    status = S_IN_ERROR;
    throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
  }
}
TOP

Related Classes of com.persiste.sdk.json.parser.JSONParser

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.