4 * License : The MIT License
\r
5 * Copyright(c) 2009 olyutorskii
\r
8 package jp.sourceforge.jindolf.json;
\r
10 import java.io.Flushable;
\r
11 import java.io.IOException;
\r
12 import java.util.Stack;
\r
16 * JSON Valueのトラバース時にこのビジターを指定すると、
\r
17 * 事前に用意した文字出力先にJSONフォーマットで出力される
\r
20 implements ValueVisitor,
\r
23 private static final String NEWLINE = "\n";
\r
24 private static final String INDENT_UNIT = "\u0020\u0020";
\r
25 private static final String HASH_SEPARATOR = "\u0020:\u0020";
\r
26 private static final String ELEM_DELIMITOR = "\u0020,";
\r
29 private final Appendable appout;
\r
31 private final Stack<JsValue> valueStack = new Stack<JsValue>();
\r
32 private final Stack<Boolean> hasChildStack = new Stack<Boolean>();
\r
34 private boolean afterPairName = false;
\r
41 public JsonAppender(Appendable appout){
\r
43 this.appout = appout;
\r
50 * @throws IOException 出力エラー
\r
52 protected void append(char ch) throws IOException{
\r
53 this.appout.append(ch);
\r
60 * @throws IOException 出力エラー
\r
62 protected void append(CharSequence seq) throws IOException{
\r
63 this.appout.append(seq);
\r
68 * 最後の改行を出力した後、可能であれば出力先をフラッシュする。
\r
69 * @throws IOException 出力エラー
\r
71 public void flush() throws IOException{
\r
73 if(this.appout instanceof Flushable){
\r
74 ((Flushable)this.appout).flush();
\r
81 * @throws IOException 出力エラー
\r
83 protected void putNewLine()
\r
91 * @throws IOException 出力エラー
\r
93 protected void indentOut() throws IOException{
\r
94 int level = stackLength();
\r
95 for(int ct = 1; ct <= level; ct++){
\r
96 append(INDENT_UNIT);
\r
103 * JSONでは最後の要素の後にコンマを出力してはいけない。
\r
104 * @throws IOException 出力エラー
\r
106 protected void putElemDelimitor()
\r
107 throws IOException{
\r
108 append(ELEM_DELIMITOR);
\r
114 * @param name pair名
\r
115 * @throws IOException 出力エラー
\r
117 protected void putPairName(String name)
\r
118 throws IOException{
\r
119 JsString.writeText(this.appout, name);
\r
125 * @throws IOException 出力エラー
\r
127 protected void putPairSeparator()
\r
128 throws IOException{
\r
129 append(HASH_SEPARATOR);
\r
135 * @param value JSON Value
\r
136 * @throws IllegalArgumentException 引数がObjectでもArrayでもなかった
\r
138 protected void pushValue(JsValue value)
\r
139 throws IllegalArgumentException{
\r
140 if( ! (value instanceof JsObject) && ! (value instanceof JsArray) ){
\r
141 throw new IllegalArgumentException();
\r
144 this.valueStack.push(value);
\r
145 this.hasChildStack.push(false);
\r
152 * @return 最後にネストしていたValue
\r
154 protected JsValue popValue(){
\r
155 this.hasChildStack.pop();
\r
156 return this.valueStack.pop();
\r
163 protected int stackLength(){
\r
164 return this.valueStack.size();
\r
168 * ネスト後、一つでも子要素が出力されたか判定する。
\r
169 * @return 子要素が出力されていればtrue
\r
171 protected boolean hasChildOut(){
\r
172 if(stackLength() <= 0) return false;
\r
173 return this.hasChildStack.peek();
\r
177 * 現時点でのネストに対し、子要素が一つ以上出力済みであると設定する。
\r
179 protected void setChildOut(){
\r
180 if(stackLength() <= 0) return;
\r
181 this.hasChildStack.pop();
\r
182 this.hasChildStack.push(true);
\r
188 * @param value {@inheritDoc}
\r
189 * @throws JsVisitException {@inheritDoc}
\r
192 public void visitValue(JsValue value)
\r
193 throws JsVisitException{
\r
195 if( ! this.afterPairName ){
\r
197 putElemDelimitor();
\r
202 this.afterPairName = false;
\r
206 if(value instanceof JsObject){
\r
209 }else if(value instanceof JsArray){
\r
213 append(value.toString());
\r
215 }catch(IOException e){
\r
216 throw new JsVisitException(e);
\r
225 * @param name {@inheritDoc}
\r
226 * @throws JsVisitException {@inheritDoc}
\r
229 public void visitPairName(String name)
\r
230 throws JsVisitException{
\r
233 putElemDelimitor();
\r
238 putPairSeparator();
\r
239 }catch(IOException e){
\r
240 throw new JsVisitException(e);
\r
244 this.afterPairName = true;
\r
252 * @param composite {@inheritDoc}
\r
253 * @throws JsVisitException {@inheritDoc}
\r
256 public void visitCollectionClose(JsValue composite)
\r
257 throws JsVisitException{
\r
258 boolean hasChild = hasChildOut();
\r
260 JsValue value = popValue();
\r
270 if(value instanceof JsObject){
\r
272 }else if(value instanceof JsArray){
\r
276 throw new JsVisitException();
\r
278 }catch(IOException e){
\r
279 throw new JsVisitException(e);
\r