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;
18 * Parser for JSON text. Please note that JSONParser is NOT thread-safe.
20 * @author FangYidong<fangyidong@yahoo.com.cn>
22 public class JSONParser
24 public static final int S_INIT = 0;
26 public static final int S_IN_FINISHED_VALUE = 1;// string,number,boolean,null,object,array
28 public static final int S_IN_OBJECT = 2;
30 public static final int S_IN_ARRAY = 3;
32 public static final int S_PASSED_PAIR_KEY = 4;
34 public static final int S_IN_PAIR_VALUE = 5;
36 public static final int S_END = 6;
38 public static final int S_IN_ERROR = -1;
40 private LinkedList handlerStatusStack;
42 private Yylex lexer = new Yylex((Reader) null);
44 private Yytoken token = null;
46 private int status = S_INIT;
48 private int peekStatus(LinkedList statusStack)
50 if (statusStack.size() == 0)
52 Integer status = (Integer) statusStack.getFirst();
53 return status.intValue();
57 * Reset the parser to the initial state without resetting the underlying
65 handlerStatusStack = null;
69 * Reset the parser to the initial state with a new character reader.
72 * - The new character reader.
74 * @throws ParseException
76 public void reset(Reader in)
83 * @return The position of the beginning of the current token.
85 public int getPosition()
87 return lexer.getPosition();
90 public Object parse(String s) throws ParseException
92 return parse(s, (ContainerFactory) null);
95 public Object parse(String s, ContainerFactory containerFactory)
98 StringReader in = new StringReader(s);
101 return parse(in, containerFactory);
102 } catch (IOException ie)
105 * Actually it will never happen.
107 throw new ParseException(-1,
108 ParseException.ERROR_UNEXPECTED_EXCEPTION, ie);
112 public Object parse(Reader in) throws IOException, ParseException
114 return parse(in, (ContainerFactory) null);
118 * Parse JSON text into java object from the input source.
121 * @param containerFactory
122 * - Use this factory to createyour own JSON object and JSON array
124 * @return Instance of the following: org.json.simple.JSONObject,
125 * org.json.simple.JSONArray, java.lang.String, java.lang.Number,
126 * java.lang.Boolean, null
128 * @throws IOException
129 * @throws ParseException
131 public Object parse(Reader in, ContainerFactory containerFactory)
132 throws IOException, ParseException
135 LinkedList statusStack = new LinkedList();
136 LinkedList valueStack = new LinkedList();
148 case Yytoken.TYPE_VALUE:
149 status = S_IN_FINISHED_VALUE;
150 statusStack.addFirst(new Integer(status));
151 valueStack.addFirst(token.value);
153 case Yytoken.TYPE_LEFT_BRACE:
154 status = S_IN_OBJECT;
155 statusStack.addFirst(new Integer(status));
156 valueStack.addFirst(createObjectContainer(containerFactory));
158 case Yytoken.TYPE_LEFT_SQUARE:
160 statusStack.addFirst(new Integer(status));
161 valueStack.addFirst(createArrayContainer(containerFactory));
168 case S_IN_FINISHED_VALUE:
169 if (token.type == Yytoken.TYPE_EOF)
170 return valueStack.removeFirst();
172 throw new ParseException(getPosition(),
173 ParseException.ERROR_UNEXPECTED_TOKEN, token);
178 case Yytoken.TYPE_COMMA:
180 case Yytoken.TYPE_VALUE:
181 if (token.value instanceof String)
183 String key = (String) token.value;
184 valueStack.addFirst(key);
185 status = S_PASSED_PAIR_KEY;
186 statusStack.addFirst(new Integer(status));
193 case Yytoken.TYPE_RIGHT_BRACE:
194 if (valueStack.size() > 1)
196 statusStack.removeFirst();
197 valueStack.removeFirst();
198 status = peekStatus(statusStack);
202 status = S_IN_FINISHED_VALUE;
211 case S_PASSED_PAIR_KEY:
214 case Yytoken.TYPE_COLON:
216 case Yytoken.TYPE_VALUE:
217 statusStack.removeFirst();
218 String key = (String) valueStack.removeFirst();
219 Map parent = (Map) valueStack.getFirst();
220 parent.put(key, token.value);
221 status = peekStatus(statusStack);
223 case Yytoken.TYPE_LEFT_SQUARE:
224 statusStack.removeFirst();
225 key = (String) valueStack.removeFirst();
226 parent = (Map) valueStack.getFirst();
227 List newArray = createArrayContainer(containerFactory);
228 parent.put(key, newArray);
230 statusStack.addFirst(new Integer(status));
231 valueStack.addFirst(newArray);
233 case Yytoken.TYPE_LEFT_BRACE:
234 statusStack.removeFirst();
235 key = (String) valueStack.removeFirst();
236 parent = (Map) valueStack.getFirst();
237 Map newObject = createObjectContainer(containerFactory);
238 parent.put(key, newObject);
239 status = S_IN_OBJECT;
240 statusStack.addFirst(new Integer(status));
241 valueStack.addFirst(newObject);
251 case Yytoken.TYPE_COMMA:
253 case Yytoken.TYPE_VALUE:
254 List val = (List) valueStack.getFirst();
255 val.add(token.value);
257 case Yytoken.TYPE_RIGHT_SQUARE:
258 if (valueStack.size() > 1)
260 statusStack.removeFirst();
261 valueStack.removeFirst();
262 status = peekStatus(statusStack);
266 status = S_IN_FINISHED_VALUE;
269 case Yytoken.TYPE_LEFT_BRACE:
270 val = (List) valueStack.getFirst();
271 Map newObject = createObjectContainer(containerFactory);
273 status = S_IN_OBJECT;
274 statusStack.addFirst(new Integer(status));
275 valueStack.addFirst(newObject);
277 case Yytoken.TYPE_LEFT_SQUARE:
278 val = (List) valueStack.getFirst();
279 List newArray = createArrayContainer(containerFactory);
282 statusStack.addFirst(new Integer(status));
283 valueStack.addFirst(newArray);
290 throw new ParseException(getPosition(),
291 ParseException.ERROR_UNEXPECTED_TOKEN, token);
293 if (status == S_IN_ERROR)
295 throw new ParseException(getPosition(),
296 ParseException.ERROR_UNEXPECTED_TOKEN, token);
298 } while (token.type != Yytoken.TYPE_EOF);
299 } catch (IOException ie)
304 throw new ParseException(getPosition(),
305 ParseException.ERROR_UNEXPECTED_TOKEN, token);
308 private void nextToken() throws ParseException, IOException
310 token = lexer.yylex();
312 token = new Yytoken(Yytoken.TYPE_EOF, null);
315 private Map createObjectContainer(ContainerFactory containerFactory)
317 if (containerFactory == null)
318 return new JSONObject();
319 Map m = containerFactory.createObjectContainer();
322 return new JSONObject();
326 private List createArrayContainer(ContainerFactory containerFactory)
328 if (containerFactory == null)
329 return new JSONArray();
330 List l = containerFactory.creatArrayContainer();
333 return new JSONArray();
337 public void parse(String s, ContentHandler contentHandler)
338 throws ParseException
340 parse(s, contentHandler, false);
343 public void parse(String s, ContentHandler contentHandler,
344 boolean isResume) throws ParseException
346 StringReader in = new StringReader(s);
349 parse(in, contentHandler, isResume);
350 } catch (IOException ie)
353 * Actually it will never happen.
355 throw new ParseException(-1,
356 ParseException.ERROR_UNEXPECTED_EXCEPTION, ie);
360 public void parse(Reader in, ContentHandler contentHandler)
361 throws IOException, ParseException
363 parse(in, contentHandler, false);
367 * Stream processing of JSON text.
369 * @see ContentHandler
372 * @param contentHandler
374 * - Indicates if it continues previous parsing operation. If set to
375 * true, resume parsing the old stream, and parameter 'in' will be
376 * ignored. If this method is called for the first time in this
377 * instance, isResume will be ignored.
379 * @throws IOException
380 * @throws ParseException
382 public void parse(Reader in, ContentHandler contentHandler,
383 boolean isResume) throws IOException, ParseException
388 handlerStatusStack = new LinkedList();
392 if (handlerStatusStack == null)
396 handlerStatusStack = new LinkedList();
400 LinkedList statusStack = handlerStatusStack;
409 contentHandler.startJSON();
413 case Yytoken.TYPE_VALUE:
414 status = S_IN_FINISHED_VALUE;
415 statusStack.addFirst(new Integer(status));
416 if (!contentHandler.primitive(token.value))
419 case Yytoken.TYPE_LEFT_BRACE:
420 status = S_IN_OBJECT;
421 statusStack.addFirst(new Integer(status));
422 if (!contentHandler.startObject())
425 case Yytoken.TYPE_LEFT_SQUARE:
427 statusStack.addFirst(new Integer(status));
428 if (!contentHandler.startArray())
436 case S_IN_FINISHED_VALUE:
438 if (token.type == Yytoken.TYPE_EOF)
440 contentHandler.endJSON();
447 throw new ParseException(getPosition(),
448 ParseException.ERROR_UNEXPECTED_TOKEN, token);
455 case Yytoken.TYPE_COMMA:
457 case Yytoken.TYPE_VALUE:
458 if (token.value instanceof String)
460 String key = (String) token.value;
461 status = S_PASSED_PAIR_KEY;
462 statusStack.addFirst(new Integer(status));
463 if (!contentHandler.startObjectEntry(key))
471 case Yytoken.TYPE_RIGHT_BRACE:
472 if (statusStack.size() > 1)
474 statusStack.removeFirst();
475 status = peekStatus(statusStack);
479 status = S_IN_FINISHED_VALUE;
481 if (!contentHandler.endObject())
490 case S_PASSED_PAIR_KEY:
494 case Yytoken.TYPE_COLON:
496 case Yytoken.TYPE_VALUE:
497 statusStack.removeFirst();
498 status = peekStatus(statusStack);
499 if (!contentHandler.primitive(token.value))
501 if (!contentHandler.endObjectEntry())
504 case Yytoken.TYPE_LEFT_SQUARE:
505 statusStack.removeFirst();
506 statusStack.addFirst(new Integer(S_IN_PAIR_VALUE));
508 statusStack.addFirst(new Integer(status));
509 if (!contentHandler.startArray())
512 case Yytoken.TYPE_LEFT_BRACE:
513 statusStack.removeFirst();
514 statusStack.addFirst(new Integer(S_IN_PAIR_VALUE));
515 status = S_IN_OBJECT;
516 statusStack.addFirst(new Integer(status));
517 if (!contentHandler.startObject())
525 case S_IN_PAIR_VALUE:
527 * S_IN_PAIR_VALUE is just a marker to indicate the end of an object entry, it doesn't proccess any token,
528 * therefore delay consuming token until next round.
530 statusStack.removeFirst();
531 status = peekStatus(statusStack);
532 if (!contentHandler.endObjectEntry())
540 case Yytoken.TYPE_COMMA:
542 case Yytoken.TYPE_VALUE:
543 if (!contentHandler.primitive(token.value))
546 case Yytoken.TYPE_RIGHT_SQUARE:
547 if (statusStack.size() > 1)
549 statusStack.removeFirst();
550 status = peekStatus(statusStack);
554 status = S_IN_FINISHED_VALUE;
556 if (!contentHandler.endArray())
559 case Yytoken.TYPE_LEFT_BRACE:
560 status = S_IN_OBJECT;
561 statusStack.addFirst(new Integer(status));
562 if (!contentHandler.startObject())
565 case Yytoken.TYPE_LEFT_SQUARE:
567 statusStack.addFirst(new Integer(status));
568 if (!contentHandler.startArray())
580 throw new ParseException(getPosition(),
581 ParseException.ERROR_UNEXPECTED_TOKEN, token);
583 if (status == S_IN_ERROR)
585 throw new ParseException(getPosition(),
586 ParseException.ERROR_UNEXPECTED_TOKEN, token);
588 } while (token.type != Yytoken.TYPE_EOF);
589 } catch (IOException ie)
593 } catch (ParseException pe)
597 } catch (RuntimeException re)
608 throw new ParseException(getPosition(),
609 ParseException.ERROR_UNEXPECTED_TOKEN, token);