2 * $Id: JSONParser.java,v 1.1 2006/04/15 14:10:48 platform Exp $
5 package org.json.simple.parser;
7 import java.io.IOException;
9 import java.io.StringReader;
10 import java.util.LinkedList;
11 import java.util.List;
14 import org.json.simple.JSONArray;
15 import org.json.simple.JSONObject;
19 * Parser for JSON text. Please note that JSONParser is NOT thread-safe.
21 * @author FangYidong<fangyidong@yahoo.com.cn>
23 public class JSONParser {
24 public static final int S_INIT=0;
25 public static final int S_IN_FINISHED_VALUE=1;//string,number,boolean,null,object,array
26 public static final int S_IN_OBJECT=2;
27 public static final int S_IN_ARRAY=3;
28 public static final int S_PASSED_PAIR_KEY=4;
29 public static final int S_IN_PAIR_VALUE=5;
30 public static final int S_END=6;
31 public static final int S_IN_ERROR=-1;
33 private LinkedList handlerStatusStack;
34 private Yylex lexer = new Yylex((Reader)null);
35 private Yytoken token = null;
36 private int status = S_INIT;
38 private int peekStatus(LinkedList statusStack){
39 if(statusStack.size()==0)
41 Integer status=(Integer)statusStack.getFirst();
42 return status.intValue();
46 * Reset the parser to the initial state without resetting the underlying reader.
52 handlerStatusStack = null;
56 * Reset the parser to the initial state with a new character reader.
58 * @param in - The new character reader.
60 * @throws ParseException
62 public void reset(Reader in){
68 * @return The position of the beginning of the current token.
70 public int getPosition(){
71 return lexer.getPosition();
74 public Object parse(String s) throws ParseException{
75 return parse(s, (ContainerFactory)null);
78 public Object parse(String s, ContainerFactory containerFactory) throws ParseException{
79 StringReader in=new StringReader(s);
81 return parse(in, containerFactory);
83 catch(IOException ie){
85 * Actually it will never happen.
87 throw new ParseException(-1, ParseException.ERROR_UNEXPECTED_EXCEPTION, ie);
91 public Object parse(Reader in) throws IOException, ParseException{
92 return parse(in, (ContainerFactory)null);
96 * Parse JSON text into java object from the input source.
99 * @param containerFactory - Use this factory to createyour own JSON object and JSON array containers.
100 * @return Instance of the following:
101 * org.json.simple.JSONObject,
102 * org.json.simple.JSONArray,
108 * @throws IOException
109 * @throws ParseException
111 public Object parse(Reader in, ContainerFactory containerFactory) throws IOException, ParseException{
113 LinkedList statusStack = new LinkedList();
114 LinkedList valueStack = new LinkedList();
122 case Yytoken.TYPE_VALUE:
123 status=S_IN_FINISHED_VALUE;
124 statusStack.addFirst(new Integer(status));
125 valueStack.addFirst(token.value);
127 case Yytoken.TYPE_LEFT_BRACE:
129 statusStack.addFirst(new Integer(status));
130 valueStack.addFirst(createObjectContainer(containerFactory));
132 case Yytoken.TYPE_LEFT_SQUARE:
134 statusStack.addFirst(new Integer(status));
135 valueStack.addFirst(createArrayContainer(containerFactory));
142 case S_IN_FINISHED_VALUE:
143 if(token.type==Yytoken.TYPE_EOF)
144 return valueStack.removeFirst();
146 throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
150 case Yytoken.TYPE_COMMA:
152 case Yytoken.TYPE_VALUE:
153 if(token.value instanceof String){
154 String key=(String)token.value;
155 valueStack.addFirst(key);
156 status=S_PASSED_PAIR_KEY;
157 statusStack.addFirst(new Integer(status));
163 case Yytoken.TYPE_RIGHT_BRACE:
164 if(valueStack.size()>1){
165 statusStack.removeFirst();
166 valueStack.removeFirst();
167 status=peekStatus(statusStack);
170 status=S_IN_FINISHED_VALUE;
179 case S_PASSED_PAIR_KEY:
181 case Yytoken.TYPE_COLON:
183 case Yytoken.TYPE_VALUE:
184 statusStack.removeFirst();
185 String key=(String)valueStack.removeFirst();
186 Map parent=(Map)valueStack.getFirst();
187 parent.put(key,token.value);
188 status=peekStatus(statusStack);
190 case Yytoken.TYPE_LEFT_SQUARE:
191 statusStack.removeFirst();
192 key=(String)valueStack.removeFirst();
193 parent=(Map)valueStack.getFirst();
194 List newArray=createArrayContainer(containerFactory);
195 parent.put(key,newArray);
197 statusStack.addFirst(new Integer(status));
198 valueStack.addFirst(newArray);
200 case Yytoken.TYPE_LEFT_BRACE:
201 statusStack.removeFirst();
202 key=(String)valueStack.removeFirst();
203 parent=(Map)valueStack.getFirst();
204 Map newObject=createObjectContainer(containerFactory);
205 parent.put(key,newObject);
207 statusStack.addFirst(new Integer(status));
208 valueStack.addFirst(newObject);
217 case Yytoken.TYPE_COMMA:
219 case Yytoken.TYPE_VALUE:
220 List val=(List)valueStack.getFirst();
221 val.add(token.value);
223 case Yytoken.TYPE_RIGHT_SQUARE:
224 if(valueStack.size()>1){
225 statusStack.removeFirst();
226 valueStack.removeFirst();
227 status=peekStatus(statusStack);
230 status=S_IN_FINISHED_VALUE;
233 case Yytoken.TYPE_LEFT_BRACE:
234 val=(List)valueStack.getFirst();
235 Map newObject=createObjectContainer(containerFactory);
238 statusStack.addFirst(new Integer(status));
239 valueStack.addFirst(newObject);
241 case Yytoken.TYPE_LEFT_SQUARE:
242 val=(List)valueStack.getFirst();
243 List newArray=createArrayContainer(containerFactory);
246 statusStack.addFirst(new Integer(status));
247 valueStack.addFirst(newArray);
254 throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
256 if(status==S_IN_ERROR){
257 throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
259 }while(token.type!=Yytoken.TYPE_EOF);
261 catch(IOException ie){
265 throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
268 private void nextToken() throws ParseException, IOException{
269 token = lexer.yylex();
271 token = new Yytoken(Yytoken.TYPE_EOF, null);
274 private Map createObjectContainer(ContainerFactory containerFactory){
275 if(containerFactory == null)
276 return new JSONObject();
277 Map m = containerFactory.createObjectContainer();
280 return new JSONObject();
284 private List createArrayContainer(ContainerFactory containerFactory){
285 if(containerFactory == null)
286 return new JSONArray();
287 List l = containerFactory.creatArrayContainer();
290 return new JSONArray();
294 public void parse(String s, ContentHandler contentHandler) throws ParseException{
295 parse(s, contentHandler, false);
298 public void parse(String s, ContentHandler contentHandler, boolean isResume) throws ParseException{
299 StringReader in=new StringReader(s);
301 parse(in, contentHandler, isResume);
303 catch(IOException ie){
305 * Actually it will never happen.
307 throw new ParseException(-1, ParseException.ERROR_UNEXPECTED_EXCEPTION, ie);
311 public void parse(Reader in, ContentHandler contentHandler) throws IOException, ParseException{
312 parse(in, contentHandler, false);
316 * Stream processing of JSON text.
318 * @see ContentHandler
321 * @param contentHandler
322 * @param isResume - Indicates if it continues previous parsing operation.
323 * If set to true, resume parsing the old stream, and parameter 'in' will be ignored.
324 * If this method is called for the first time in this instance, isResume will be ignored.
326 * @throws IOException
327 * @throws ParseException
329 public void parse(Reader in, ContentHandler contentHandler, boolean isResume) throws IOException, ParseException{
332 handlerStatusStack = new LinkedList();
335 if(handlerStatusStack == null){
338 handlerStatusStack = new LinkedList();
342 LinkedList statusStack = handlerStatusStack;
348 contentHandler.startJSON();
351 case Yytoken.TYPE_VALUE:
352 status=S_IN_FINISHED_VALUE;
353 statusStack.addFirst(new Integer(status));
354 if(!contentHandler.primitive(token.value))
357 case Yytoken.TYPE_LEFT_BRACE:
359 statusStack.addFirst(new Integer(status));
360 if(!contentHandler.startObject())
363 case Yytoken.TYPE_LEFT_SQUARE:
365 statusStack.addFirst(new Integer(status));
366 if(!contentHandler.startArray())
374 case S_IN_FINISHED_VALUE:
376 if(token.type==Yytoken.TYPE_EOF){
377 contentHandler.endJSON();
383 throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
389 case Yytoken.TYPE_COMMA:
391 case Yytoken.TYPE_VALUE:
392 if(token.value instanceof String){
393 String key=(String)token.value;
394 status=S_PASSED_PAIR_KEY;
395 statusStack.addFirst(new Integer(status));
396 if(!contentHandler.startObjectEntry(key))
403 case Yytoken.TYPE_RIGHT_BRACE:
404 if(statusStack.size()>1){
405 statusStack.removeFirst();
406 status=peekStatus(statusStack);
409 status=S_IN_FINISHED_VALUE;
411 if(!contentHandler.endObject())
420 case S_PASSED_PAIR_KEY:
423 case Yytoken.TYPE_COLON:
425 case Yytoken.TYPE_VALUE:
426 statusStack.removeFirst();
427 status=peekStatus(statusStack);
428 if(!contentHandler.primitive(token.value))
430 if(!contentHandler.endObjectEntry())
433 case Yytoken.TYPE_LEFT_SQUARE:
434 statusStack.removeFirst();
435 statusStack.addFirst(new Integer(S_IN_PAIR_VALUE));
437 statusStack.addFirst(new Integer(status));
438 if(!contentHandler.startArray())
441 case Yytoken.TYPE_LEFT_BRACE:
442 statusStack.removeFirst();
443 statusStack.addFirst(new Integer(S_IN_PAIR_VALUE));
445 statusStack.addFirst(new Integer(status));
446 if(!contentHandler.startObject())
454 case S_IN_PAIR_VALUE:
456 * S_IN_PAIR_VALUE is just a marker to indicate the end of an object entry, it doesn't proccess any token,
457 * therefore delay consuming token until next round.
459 statusStack.removeFirst();
460 status = peekStatus(statusStack);
461 if(!contentHandler.endObjectEntry())
468 case Yytoken.TYPE_COMMA:
470 case Yytoken.TYPE_VALUE:
471 if(!contentHandler.primitive(token.value))
474 case Yytoken.TYPE_RIGHT_SQUARE:
475 if(statusStack.size()>1){
476 statusStack.removeFirst();
477 status=peekStatus(statusStack);
480 status=S_IN_FINISHED_VALUE;
482 if(!contentHandler.endArray())
485 case Yytoken.TYPE_LEFT_BRACE:
487 statusStack.addFirst(new Integer(status));
488 if(!contentHandler.startObject())
491 case Yytoken.TYPE_LEFT_SQUARE:
493 statusStack.addFirst(new Integer(status));
494 if(!contentHandler.startArray())
506 throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
508 if(status==S_IN_ERROR){
509 throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
511 }while(token.type!=Yytoken.TYPE_EOF);
513 catch(IOException ie){
517 catch(ParseException pe){
521 catch(RuntimeException re){
531 throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);