1 /*--------------------------------------------------------------------------
\r
2 * Copyright 2007 Taro L. Saito
\r
4 * Licensed under the Apache License, Version 2.0 (the "License");
\r
5 * you may not use this file except in compliance with the License.
\r
6 * You may obtain a copy of the License at
\r
8 * http://www.apache.org/licenses/LICENSE-2.0
\r
10 * Unless required by applicable law or agreed to in writing, software
\r
11 * distributed under the License is distributed on an "AS IS" BASIS,
\r
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
13 * See the License for the specific language governing permissions and
\r
14 * limitations under the License.
\r
15 *--------------------------------------------------------------------------*/
\r
16 //--------------------------------------
\r
19 // JSONPullParser.java
\r
20 // Since: May 8, 2007
\r
22 // $URL: http://dev.utgenome.org/svn/utgb/trunk/common/src/org/utgenome/json/JSONPullParser.java $
\r
24 //--------------------------------------
\r
25 package org.xerial.json;
\r
27 import java.io.IOException;
\r
28 import java.io.InputStream;
\r
29 import java.io.Reader;
\r
31 import org.antlr.runtime.ANTLRInputStream;
\r
32 import org.antlr.runtime.ANTLRReaderStream;
\r
33 import org.antlr.runtime.ANTLRStringStream;
\r
34 import org.antlr.runtime.CharStream;
\r
35 import org.antlr.runtime.Token;
\r
36 import org.xerial.json.impl.JSONLexer;
\r
37 import org.xerial.util.ArrayDeque;
\r
38 import org.xerial.util.log.Logger;
\r
41 * Pull Parser for JSON data
\r
46 public class JSONPullParser
\r
48 private static enum ParseState {
\r
49 Root, InObject, InArray, Key, KeyedValue
\r
52 private static Logger _logger = Logger.getLogger(JSONPullParser.class);
\r
53 private JSONLexer _lexer = new JSONLexer();
\r
55 private ArrayDeque<ParseState> parseStateStack = new ArrayDeque<ParseState>();
\r
56 private ArrayDeque<String> keyStack = new ArrayDeque<String>();
\r
58 private JSONPullParserEvent lastReportedEvent = null;
\r
59 private int currentDepth = 0;
\r
61 public JSONPullParser(String jsonString)
\r
66 public JSONPullParser(JSONObject jsonObject)
\r
71 public JSONPullParser(InputStream jsonStream) throws IOException
\r
76 public JSONPullParser(Reader reader) throws IOException
\r
81 public void reset(String jsonString)
\r
83 reset(new ANTLRStringStream(jsonString));
\r
86 public void reset(JSONObject jsonObject)
\r
88 reset(new ANTLRStringStream(jsonObject.toJSONString()));
\r
91 public void reset(InputStream jsonStream) throws IOException
\r
93 reset(new ANTLRInputStream(jsonStream));
\r
96 public void reset(Reader reader) throws IOException
\r
98 reset(new ANTLRReaderStream(reader));
\r
101 private void reset(CharStream newStream)
\r
104 _lexer.setCharStream(newStream);
\r
106 parseStateStack.clear();
\r
109 lastReportedEvent = null;
\r
112 parseStateStack.addLast(ParseState.Root);
\r
115 private ParseState getCurrentParseState()
\r
117 return parseStateStack.getLast();
\r
120 private void validateParseState(ParseState... possibleParseState) throws JSONException
\r
122 ParseState current = getCurrentParseState();
\r
123 for (ParseState ps : possibleParseState)
\r
128 throw new JSONException(JSONErrorCode.InvalidJSONData, "invalid parse state: " + current.name() + " line = "
\r
129 + _lexer.getLine());
\r
132 private void popKeyStack()
\r
134 if (getCurrentParseState() == ParseState.Key)
\r
135 keyStack.removeLast();
\r
138 private void pushParseState(ParseState ps)
\r
140 parseStateStack.addLast(ps);
\r
141 // _logger.trace("push: " + StringUtil.join(parseStateStack, ", "));
\r
144 private void popParseState()
\r
146 parseStateStack.removeLast();
\r
147 // _logger.trace("pop : " + StringUtil.join(parseStateStack, ", "));
\r
150 private void valueWithKeyTest()
\r
152 if (getCurrentParseState() == ParseState.Key)
\r
153 pushParseState(ParseState.KeyedValue);
\r
157 * Reads the current JSONValue, which is one of {@link JSONObject} ,
\r
158 * {@link JSONArray}, {@link JSONInteger}, {@link JSONDouble},
\r
159 * {@link JSONString}, {@link JSONBoolean} and {@link JSONNull}. This
\r
160 * methods proceeds the parse state up to the end of the returned value.
\r
162 * @return the current JSONValue
\r
163 * @throws JSONException
\r
164 * when the current token is not a {@link JSONValue}
\r
166 public JSONValue getValue() throws JSONException
\r
168 if (lastReportedEvent == null)
\r
171 while (lastReportedEvent.getEvent() != JSONEvent.EndJSON)
\r
173 switch (lastReportedEvent.getEvent())
\r
176 return new JSONString(getText());
\r
178 return new JSONInteger(getText());
\r
180 return new JSONDouble(getText());
\r
182 return new JSONBoolean(getText());
\r
184 return new JSONNull();
\r
186 return readJSONObject(new JSONObject(), getDepth());
\r
188 return readJSONArray(new JSONArray(), getDepth());
\r
193 throw new JSONException(JSONErrorCode.JSONValueIsNotFound);
\r
197 * Reads the current JSONValue as String data
\r
200 * @throws JSONException
\r
202 public String getValueAsText() throws JSONException
\r
204 if (lastReportedEvent == null)
\r
207 while (lastReportedEvent.getEvent() != JSONEvent.EndJSON)
\r
209 switch (lastReportedEvent.getEvent())
\r
218 return readJSONObject(new JSONObject(), getDepth()).toJSONString();
\r
220 return readJSONArray(new JSONArray(), getDepth()).toJSONString();
\r
225 throw new JSONException(JSONErrorCode.JSONValueIsNotFound);
\r
229 private JSONObject readJSONObject(JSONObject jsonObject, int baseObjectDepth) throws JSONException
\r
233 JSONEvent event = next();
\r
237 jsonObject.put(getKeyName(), readJSONObject(new JSONObject(), getDepth()));
\r
240 if (getDepth() < baseObjectDepth)
\r
243 throw new JSONException(JSONErrorCode.ParseError);
\r
245 jsonObject.put(getKeyName(), readJSONArray(new JSONArray(), getDepth()));
\r
248 throw new JSONException(JSONErrorCode.NotInAJSONObject);
\r
254 jsonObject.put(getKeyName(), getValue());
\r
258 throw new JSONException(JSONErrorCode.UnexpectedEndOfJSON);
\r
263 private JSONArray readJSONArray(JSONArray jsonArray, int baseArrayDepth) throws JSONException
\r
267 JSONEvent event = next();
\r
271 jsonArray.add(readJSONObject(new JSONObject(), getDepth()));
\r
274 throw new JSONException(JSONErrorCode.ParseError);
\r
276 jsonArray.add(readJSONArray(new JSONArray(), getDepth()));
\r
279 if (getDepth() < baseArrayDepth)
\r
282 throw new JSONException(JSONErrorCode.ParseError);
\r
288 jsonArray.add(getValue());
\r
292 throw new JSONException(JSONErrorCode.UnexpectedEndOfJSON);
\r
298 * Reads the next {@link JSONEvent}
\r
300 * @return the next {@link JSONEvent}. If no more token is available,
\r
301 * returns {@link JSONEvent#EndJSON}.
\r
302 * @throws JSONException
\r
303 * when some syntax error is found.
\r
305 public JSONEvent next() throws JSONException
\r
308 while ((token = _lexer.nextToken()) != Token.EOF_TOKEN)
\r
310 if (getCurrentParseState() == ParseState.KeyedValue)
\r
312 keyStack.removeLast();
\r
314 if (getCurrentParseState() == ParseState.Key)
\r
317 throw new JSONException(JSONErrorCode.ParseError);
\r
320 int tokenType = token.getType();
\r
324 case JSONLexer.LBrace:
\r
325 valueWithKeyTest();
\r
327 pushParseState(ParseState.InObject);
\r
328 return reportEvent(token, JSONEvent.StartObject);
\r
329 case JSONLexer.RBrace:
\r
331 validateParseState(ParseState.InObject);
\r
334 return reportEvent(token, JSONEvent.EndObject);
\r
335 case JSONLexer.LBracket:
\r
336 valueWithKeyTest();
\r
338 pushParseState(ParseState.InArray);
\r
339 return reportEvent(token, JSONEvent.StartArray);
\r
340 case JSONLexer.RBracket:
\r
342 validateParseState(ParseState.InArray);
\r
345 return reportEvent(token, JSONEvent.EndArray);
\r
346 case JSONLexer.Comma:
\r
347 validateParseState(ParseState.InArray, ParseState.InObject);
\r
349 case JSONLexer.Colon:
\r
350 validateParseState(ParseState.Key); // next sequence will be a
\r
353 case JSONLexer.String:
\r
354 if (getCurrentParseState() == ParseState.InObject)
\r
357 pushParseState(ParseState.Key);
\r
358 keyStack.addLast(removeDoubleQuotation(token.getText()));
\r
361 valueWithKeyTest();
\r
362 return reportEvent(token, JSONEvent.String);
\r
363 case JSONLexer.Integer:
\r
364 valueWithKeyTest();
\r
365 return reportEvent(token, JSONEvent.Integer);
\r
366 case JSONLexer.Double:
\r
367 valueWithKeyTest();
\r
368 return reportEvent(token, JSONEvent.Double);
\r
369 case JSONLexer.TRUE:
\r
370 case JSONLexer.FALSE:
\r
371 valueWithKeyTest();
\r
372 return reportEvent(token, JSONEvent.Boolean);
\r
373 case JSONLexer.NULL:
\r
374 valueWithKeyTest();
\r
375 return reportEvent(token, JSONEvent.Null);
\r
379 return JSONEvent.EndJSON;
\r
382 protected JSONEvent reportEvent(Token token, JSONEvent e)
\r
384 lastReportedEvent = new JSONPullParserEvent(token, e);
\r
385 return lastReportedEvent.getEvent();
\r
389 * Gets the current object/array/value key.
\r
391 * @return the current key, or null when the current token is no name array
\r
393 * @throws JSONException
\r
395 public String getKeyName() throws JSONException
\r
397 if (keyStack.isEmpty())
\r
400 return keyStack.getLast();
\r
403 public String getText()
\r
405 if (lastReportedEvent.getEvent() == JSONEvent.String)
\r
406 return removeDoubleQuotation(lastReportedEvent.getToken().getText());
\r
408 return lastReportedEvent.getToken().getText();
\r
411 private static String removeDoubleQuotation(String text)
\r
413 return text.substring(1, text.length() - 1);
\r
416 public int getDepth()
\r
418 return currentDepth;
\r
424 * A pull parser event
\r
429 class JSONPullParserEvent
\r
432 private JSONEvent event;
\r
434 public JSONPullParserEvent(Token t, JSONEvent event)
\r
437 this.event = event;
\r
440 public Token getToken()
\r
445 public void setToken(Token t)
\r
450 public JSONEvent getEvent()
\r
455 public void setEvent(JSONEvent event)
\r
457 this.event = event;
\r