wink-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ngalla...@apache.org
Subject svn commit: r1021933 [5/9] - in /incubator/wink/trunk: ./ wink-json4j/ wink-json4j/src/ wink-json4j/src/main/ wink-json4j/src/main/java/ wink-json4j/src/main/java/org/ wink-json4j/src/main/java/org/apache/ wink-json4j/src/main/java/org/apache/wink/ win...
Date Tue, 12 Oct 2010 21:30:32 GMT
Added: incubator/wink/trunk/wink-json4j/src/main/java/org/apache/wink/json4j/internal/Tokenizer.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-json4j/src/main/java/org/apache/wink/json4j/internal/Tokenizer.java?rev=1021933&view=auto
==============================================================================
--- incubator/wink/trunk/wink-json4j/src/main/java/org/apache/wink/json4j/internal/Tokenizer.java (added)
+++ incubator/wink/trunk/wink-json4j/src/main/java/org/apache/wink/json4j/internal/Tokenizer.java Tue Oct 12 21:30:30 2010
@@ -0,0 +1,622 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+
+package org.apache.wink.json4j.internal;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.BufferedReader;
+import java.io.StringReader;
+import java.io.CharArrayReader;
+import java.io.PushbackReader;
+
+/**
+ * Tokenizes a stream into JSON tokens.
+ */
+public class Tokenizer {
+
+    /**
+     * The reader from which the JSON string is being read.
+     */
+    private Reader reader;
+
+    /** 
+     * The current line position in the JSON string.
+     */
+    private int     lineNo;
+
+    /**
+     * The current column position in the JSON string.
+     */
+    private int     colNo;
+
+    /** 
+     * The last character read from the JSON string.
+     */
+    private int     lastChar;
+
+    /**
+     * Whether or not the parser should be spec strict, or allow unquoted strings and comments
+     */
+    private boolean strict = false;
+
+    /**
+     * Constructor.
+     * @param reader The reader from which the JSON string is read.  Same as Tokenizer(reader, false);
+     * 
+     * @throws IOException Thrown on IOErrors such as invalid JSON or sudden reader closures.
+     */
+    public Tokenizer(Reader reader) throws IOException {
+        super();
+
+        Class readerClass= reader.getClass();
+        //In-memory readers don't need to be buffered.  Also, skip PushbackReaders
+        //because they probably already wrap a buffered stream.  And lastly, anything
+        //that extends from a BufferedReader also doesn't need buffering!
+        if (!StringReader.class.isAssignableFrom(readerClass) && 
+            !CharArrayReader.class.isAssignableFrom(readerClass) &&
+            !PushbackReader.class.isAssignableFrom(readerClass) &&
+            !BufferedReader.class.isAssignableFrom(readerClass)) {
+            reader = new BufferedReader(reader);
+        }
+        this.reader    = reader;
+        this.lineNo    = 0;
+        this.colNo     = 0;
+        this.lastChar  = '\n';
+        readChar();
+    }
+
+    /**
+     * Constructor.
+     * @param reader The reader from which the JSON string is read.
+     * @param strict Whether or not the parser should be spec strict, or allow unquoted strings and comments.
+     * 
+     * @throws IOException Thrown on IOErrors such as invalid JSON or sudden reader closures.
+     */
+    public Tokenizer(Reader reader, boolean strict) throws IOException {
+        super();
+
+        Class readerClass= reader.getClass();
+        //In-memory readers don't need to be buffered.  Also, skip PushbackReaders
+        //because they probably already wrap a buffered stream.  And lastly, anything
+        //that extends from a BufferedReader also doesn't need buffering!
+        if (!StringReader.class.isAssignableFrom(readerClass) && 
+            !CharArrayReader.class.isAssignableFrom(readerClass) &&
+            !PushbackReader.class.isAssignableFrom(readerClass) &&
+            !BufferedReader.class.isAssignableFrom(readerClass)) {
+            reader = new BufferedReader(reader);
+        }
+        this.reader    = reader;
+        this.lineNo    = 0;
+        this.colNo     = 0;
+        this.lastChar  = '\n';
+        this.strict    = strict;
+
+        readChar();
+    }
+
+    /**
+     * Method to get the next JSON token from the JSON String
+     * @return The next token in the stream, returning Token.TokenEOF when finished.
+     *
+     * @throws IOException Thrown if unexpected read error occurs or invalid character encountered in JSON string.
+     */
+    public Token next() throws IOException {
+
+        // skip whitespace, use our own checker, it seems
+        // a bit faster than Java's default.
+        //while (Character.isWhitespace((char)lastChar)) {
+        while (isWhitespace((char)lastChar)) {
+            readChar();
+        }
+
+        // handle punctuation
+        switch (lastChar) {
+            case -1:  readChar(); return Token.TokenEOF;
+            case '{': readChar(); return Token.TokenBraceL;
+            case '}': readChar(); return Token.TokenBraceR;
+            case '[': readChar(); return Token.TokenBrackL;
+            case ']': readChar(); return Token.TokenBrackR;
+            case ':': readChar(); return Token.TokenColon;
+            case ',': readChar(); return Token.TokenComma;
+
+            case '"':
+            case '\'':
+                String stringValue = readString();
+                return new Token(stringValue);
+
+            case '-':
+            case '.':
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+                Number numberValue = readNumber();
+                return new Token(numberValue);
+
+            case 'n': 
+            case 't':
+            case 'f':
+                String ident = readIdentifier();
+
+                if (ident.equals("null"))  return Token.TokenNull;
+                if (ident.equals("true"))  return Token.TokenTrue;
+                if (ident.equals("false")) return Token.TokenFalse;
+
+                // Okay, this was some sort of unquoted string, may be okay
+                if (!this.strict) {
+                    //Unquoted string.  Non-strict mode allows this.  It's still bad input 
+                    //from a spec perspective, but allowable in non-strict mode.
+                    return new Token(ident);
+                } else {
+                    throw new IOException("Unexpected unquoted string literal: [" + ident + "].  Unquoted strings are not allowed in strict mode");
+                }
+            case '/':
+                if (!this.strict) {
+                    // Comment mode and not strict.  Lets just devour the comment.
+                    readComment();
+                    return next();
+                } else {
+                    throw new IOException("Unexpected character / encountered " + onLineCol() + ".  Comments are not allowed in strict mode");
+                }
+
+            default:
+                if (!this.strict && isValidUnquotedChar((char)lastChar)) {
+                    // Unquoted string.  Bad form, but ... okay, lets accept it.
+                    // some other parsers do.
+                    String unquotedStr = readIdentifier();
+                    return new Token(unquotedStr);
+                } else {
+                    if (this.strict) {
+                        throw new IOException("Unexpected character '" + (char)lastChar + "' " + onLineCol() + ".  Unquoted strings are not allowed in strict mode.");
+                    } else {
+                        throw new IOException("Unexpected character '" + (char)lastChar + "' " + onLineCol());
+                    }
+                }
+        }
+
+    }
+
+    /**
+     * Method to read out comments in the 'JSON'.  JSON normally should not
+     * have comments, but I guess we need to be more permissive to make some Crockford code
+     * happy.
+     */
+    private void readComment() throws IOException {
+        readChar();
+        if ((char)lastChar == '/') {
+            // Okay, // comment,so just read to \n or end of line
+            while ((char)lastChar != '\n' && lastChar != -1) {
+                readChar();
+            }
+        } else if ((char)lastChar == '*') {
+            // /* comment, so read past it.
+            char[] chars = new char[2];
+            readChar();
+            if (lastChar != -1) {
+                chars[0] = (char)lastChar;
+            } else {
+                return;
+            }
+            readChar();
+            if (lastChar != -1) {
+                chars[1] = (char)lastChar;
+            } else {
+                return;
+            }
+
+            while (chars[0] != '*' || chars[1] != '/') {
+                readChar();
+                if (lastChar != -1) {
+                    chars[0] = chars[1];
+                    chars[1] = (char)lastChar;
+                 
+                } else {
+                    return;
+                }
+            }
+        }
+    }
+
+    /**
+     * Method to read a string from the JSON string, converting escapes accordingly.
+     * @return The parsed JSON string with all escapes properly converyed.
+     *
+     * @throws IOException Thrown on unterminated strings, invalid characters, bad escapes, and so on.  Basically, invalid JSON.
+     */
+    private String readString() throws IOException {
+        StringBuffer sb    = new StringBuffer();
+        int          delim = lastChar;
+        int          l = lineNo;
+        int          c = colNo;
+
+        readChar();
+        while ((-1 != lastChar) && (delim != lastChar)) {
+            StringBuffer digitBuffer;
+
+            if (lastChar != '\\') {
+                sb.append((char)lastChar);
+                readChar();
+                continue;
+            }
+
+            readChar();
+
+            switch (lastChar) {
+                case 'b':  readChar(); sb.append('\b'); continue; 
+                case 'f':  readChar(); sb.append('\f'); continue; 
+                case 'n':  readChar(); sb.append('\n'); continue; 
+                case 'r':  readChar(); sb.append('\r'); continue; 
+                case 't':  readChar(); sb.append('\t'); continue; 
+                case '\'': readChar(); sb.append('\''); continue; 
+                case '"':  readChar(); sb.append('"');  continue; 
+                case '\\': readChar(); sb.append('\\'); continue;
+                case '/': readChar();  sb.append('/'); continue;
+
+                    // hex constant
+                    // unicode constant
+                case 'x':
+                case 'u':
+                    digitBuffer = new StringBuffer();
+
+                    int toRead = 2;
+                    if (lastChar == 'u') toRead = 4;
+
+                    for (int i=0; i<toRead; i++) {
+                        readChar();
+                        if (!isHexDigit(lastChar)) throw new IOException("non-hex digit " + onLineCol());
+                        digitBuffer.append((char) lastChar);
+                    }
+                    readChar();
+
+                    try {
+                        int digitValue = Integer.parseInt(digitBuffer.toString(), 16);
+                        sb.append((char) digitValue);
+                    } catch (NumberFormatException e) {
+                        throw new IOException("non-hex digit " + onLineCol());
+                    }
+
+                    break;
+
+                    // octal constant
+                default:
+                    if (!isOctalDigit(lastChar)) throw new IOException("non-hex digit " + onLineCol());
+
+                    digitBuffer = new StringBuffer();
+                    digitBuffer.append((char) lastChar);
+
+                    for (int i=0; i<2; i++) {
+                        readChar();
+                        if (!isOctalDigit(lastChar)) break;
+
+                        digitBuffer.append((char) lastChar);
+                    }
+
+                    try {
+                        int digitValue = Integer.parseInt(digitBuffer.toString(), 8);
+                        sb.append((char) digitValue);
+                    } catch (NumberFormatException e) {
+                        throw new IOException("non-hex digit " + onLineCol());
+                    }
+            }
+        }
+
+        if (-1 == lastChar) {
+            throw new IOException("String not terminated " + onLineCol(l,c));
+        }
+
+        readChar();
+
+        return sb.toString();
+    }
+
+    /**
+     * Method to read a number from the JSON string.
+     * 
+     * (-)(1-9)(0-9)*            : decimal
+     * (-)0(0-7)*               : octal
+     * (-)0(x|X)(0-9|a-f|A-F)*  : hex
+     * [digits][.digits][(E|e)[(+|-)]digits]         
+     *
+     * @returns The number as the wrapper Java Number type.
+     * 
+     * @throws IOException Thrown in invalid numbers or unexpected end of JSON string
+     * */
+    private Number readNumber() throws IOException {
+        StringBuffer sb = new StringBuffer();
+        int          l    = lineNo;
+        int          c    = colNo;
+
+
+        boolean isHex = false;
+        
+        if (lastChar == '-') {
+        	sb.append((char)lastChar);
+            readChar();
+        }
+        if (lastChar == '0') {
+        	sb.append((char)lastChar);
+            readChar();
+        	if (lastChar == 'x' || lastChar == 'X') {
+        		sb.append((char)lastChar);
+                readChar();
+        		isHex = true;
+        	}
+        }
+        
+        if (isHex) {
+        	while (isDigitChar(lastChar) || isHexDigit(lastChar)) {
+                sb.append((char)lastChar);
+                readChar();
+            }  	   
+        }
+        else {
+            while (isDigitChar(lastChar)) {
+                sb.append((char)lastChar);
+                readChar();
+            } 
+        }
+
+        // convert it!
+        String string = sb.toString();
+
+        try {
+            if (-1 != string.indexOf('.')) {
+                return Double.valueOf(string);
+            }
+
+            String sign = "";
+            if (string.startsWith("-")) {
+                sign = "-";
+                string = string.substring(1);
+            }
+
+            if (isHex) {
+            	Long value = Long.valueOf(sign + string.substring(2),16);
+                if (value.longValue() <= Integer.MAX_VALUE  && (value.longValue() >= Integer.MIN_VALUE)) {
+                	return new Integer(value.intValue());
+                }
+                else {
+                	return value;
+                }
+            }
+
+            if (string.equals("0")) {
+                return new Integer(0);
+            } else if (string.startsWith("0") && string.length() > 1) {
+            	Long value = Long.valueOf(sign + string.substring(1),8);
+                if (value.longValue() <= Integer.MAX_VALUE  && (value.longValue() >= Integer.MIN_VALUE)) {
+                	return new Integer(value.intValue());
+                }
+                else {
+                	return value;
+                }
+            }
+
+            /**
+             * We have to check for the exponential and treat appropriately
+             * Exponentials should be treated as Doubles.
+             */
+            if (string.indexOf("e") != -1 || string.indexOf("E") != -1) {
+                return Double.valueOf(sign + string);
+            } else {
+            	Long value = Long.valueOf(sign + string,10);
+                if (value.longValue() <= Integer.MAX_VALUE  && (value.longValue() >= Integer.MIN_VALUE)) {
+                	return new Integer(value.intValue());
+                }
+                else {
+                	return value;
+                }
+            }
+        } catch (NumberFormatException e) {
+            IOException iox = new IOException("Invalid number literal " + onLineCol(l,c));
+            iox.initCause(e);
+            throw iox;
+        }
+    }
+
+    /**
+     * Method to indicate if the character read is a HEX digit or not. 
+     * @param c The character to check for being a HEX digit.
+     */
+    private boolean isHexDigit(int c) {
+        switch (c) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4': 
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            case 'A':
+            case 'B':
+            case 'C':
+            case 'D':
+            case 'E':
+            case 'F':
+            case 'a':
+            case 'b':
+            case 'c':
+            case 'd':
+            case 'e':
+            case 'f':
+                return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Method to indicate if the character read is an OCTAL digit or not. 
+     * @param c The character to check for being a OCTAL digit.
+     */
+    private boolean isOctalDigit(int c) {
+        switch (c) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4': 
+            case '5':
+            case '6':
+            case '7': 
+                return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Method to indicate if the character read is a digit or not.  
+     * @param c The character to check for being a digit.
+     */
+    private boolean isDigitChar(int c) {
+        switch (c) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4': 
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            case '.':
+            case 'e':
+            case 'E':
+            case 'x':
+            case 'X':
+            case '+':
+            case '-':
+                return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Method to read a partular character string.
+     * only really need to handle 'null', 'true', and 'false' 
+     */
+    private String readIdentifier() throws IOException {
+        StringBuffer sb = new StringBuffer();
+        
+        if (this.strict) {
+        	while ((-1 != lastChar) && (Character.isLetter((char)lastChar))) {
+                sb.append((char)lastChar);
+                readChar();
+            }
+        }
+        else {
+            while ((-1 != lastChar) && isValidUnquotedChar((char)lastChar)) {
+               sb.append((char)lastChar);
+               readChar();
+           }
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Method to read the next character from the string, keeping track of line/column position.
+     * 
+     * @throws IOEXception Thrown when underlying reader throws an error.
+     */
+    private void readChar() throws IOException {
+        if ('\n' == lastChar) {
+            this.colNo = 0;
+            this.lineNo++;
+        }
+        lastChar = reader.read();
+        if (-1 == lastChar) return ;
+        colNo++;
+    }
+
+    /**
+     * Method to generate a String indicationg the current line and column position in the JSON string.
+     */
+    private String onLineCol(int line, int col) {
+        return "on line " + line + ", column " + col;
+    }
+
+    /**
+     * Method to generate a String indicationg the current line and column position in the JSON string.
+     */
+    public String onLineCol() {
+        return onLineCol(lineNo,colNo);
+    }
+
+    /**
+     * High speed test for whitespace!  Faster than the java one (from some testing).
+     * @return if the indicated character is whitespace.
+     */
+    public boolean isWhitespace(char c) {
+        switch (c) {
+            case 9:  //'unicode: 0009
+            case 10: //'unicode: 000A'
+            case 11: //'unicode: 000B'
+            case 12: //'unicode: 000C'
+            case 13: //'unicode: 000D'
+            case 28: //'unicode: 001C'
+            case 29: //'unicode: 001D'
+            case 30: //'unicode: 001E'
+            case 31: //'unicode: 001F'
+            case ' ': // Space
+                //case Character.SPACE_SEPARATOR:
+                //case Character.LINE_SEPARATOR:
+            case Character.PARAGRAPH_SEPARATOR:
+                return true;
+        }
+        return false;
+    }
+    
+    /**
+     * For non strict mode, check if char is valid when not quoted.
+     * @param c
+     * @return if character is valid unquoted character.
+     */
+    public boolean isValidUnquotedChar(char c) {
+    	
+    	if (Character.isLetterOrDigit(c)) {
+    		return true;
+    	}
+    	
+    	switch (c) {
+          case '@':  
+          case '-':  
+          case '.':  
+          case '$': 
+          case '+': 
+          case '!': 
+          case '_':
+              return true;
+    	}
+        return false; 
+    }
+}

Added: incubator/wink/trunk/wink-json4j/src/main/java/org/apache/wink/json4j/utils/XML.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-json4j/src/main/java/org/apache/wink/json4j/utils/XML.java?rev=1021933&view=auto
==============================================================================
--- incubator/wink/trunk/wink-json4j/src/main/java/org/apache/wink/json4j/utils/XML.java (added)
+++ incubator/wink/trunk/wink-json4j/src/main/java/org/apache/wink/json4j/utils/XML.java Tue Oct 12 21:30:30 2010
@@ -0,0 +1,683 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+
+package org.apache.wink.json4j.utils;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import java.util.StringTokenizer;
+import java.io.File;
+import java.io.InputStream;
+import java.io.BufferedInputStream;
+import java.io.OutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.UnsupportedEncodingException;
+import java.io.IOException;
+import java.util.logging.*;
+
+/**
+ * Used for conversion of JSON -> XML.
+ */
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.Document;
+import java.util.Properties;
+import java.util.Iterator;
+import java.util.Set;
+import java.io.StringReader;
+
+
+
+import org.apache.wink.json4j.JSONArray;
+import org.apache.wink.json4j.JSONObject;
+import org.apache.wink.json4j.utils.internal.JSONSAXHandler;
+
+
+/**
+ * This class is a static helper for various ways of converting an XML document/InputStream 
+ * into a JSON stream or String and vice-versa.
+ * 
+ * For example, the XML document:<br>
+ * <xmp>
+ *   <getValuesReturn return="true">
+ *     <attribute attrValue="value"/>
+ *     <String>First item</String>
+ *     <String>Second item</String>
+ *     <String>Third item</String>
+ *     <TextTag>Text!</TextTag>
+ *     <EmptyTag/>
+ *     <TagWithAttrs attr1="value1" attr2="value2" attr3="value3"/>
+ *     <TagWithAttrsAndText attr1="value1" attr2="value2" attr3="value3">Text!</TagWithAttrsAndText>
+ *   </getValuesReturn>
+ * </xmp>
+ * <br>
+ * in JSON (in non-compact form) becomes<br>
+ * <xmp>
+ * {
+ *    "getValuesReturn" : {
+ *       "return" : "true",
+ *       "TextTag" : "Text!",
+ *       "String" : [
+ *          "First item",
+ *          "Second item",
+ *          "Third item"
+ *       ],
+ *       "TagWithAttrsAndText" : {
+ *          "content" : "Text!",
+ *          "attr3" : "value3",
+ *          "attr2" : "value2",
+ *          "attr1" : "value1"
+ *       }
+ *       ,
+ *       "EmptyTag" : true,
+ *       "attribute" : {
+ *          "attrValue" : "value"
+ *       }
+ *       ,
+ *       "TagWithAttrs" : {
+ *          "attr3" : "value3",
+ *          "attr2" : "value2",
+ *          "attr1" : "value1"
+ *       }
+ *    }
+ * } 
+ * </xmp>
+ */
+public class XML {
+    /**
+     * Logger init.
+     */
+    private static String  className              = "org.apache.commons.json.xml.transform.XML";
+    private static Logger logger                  = Logger.getLogger(className,null);
+
+    /**
+     * Stylesheet for just doing indention.
+     */
+    private static final String styleSheet= " <xsl:stylesheet version=\"1.0\"                                   \n" +
+                                            "     xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">           \n" +
+                                            "   <xsl:output method=\"xml\"/>                                    \n" +
+                                            "   <xsl:param name=\"indent-increment\" select=\"'   '\" />        \n" +
+                                            "   <xsl:template match=\"*\">                                      \n" +
+                                            "      <xsl:param name=\"indent\" select=\"'&#xA;'\"/>              \n" +
+                                            "      <xsl:value-of select=\"$indent\"/>                           \n" +
+                                            "      <xsl:copy>                                                   \n" +
+                                            "        <xsl:copy-of select=\"@*\" />                              \n" +
+                                            "        <xsl:apply-templates>                                      \n" +
+                                            "          <xsl:with-param name=\"indent\"                          \n" +
+                                            "               select=\"concat($indent, $indent-increment)\"/>     \n" +
+                                            "        </xsl:apply-templates>                                     \n" +
+                                            "        <xsl:if test=\"*\">                                        \n" +
+                                            "          <xsl:value-of select=\"$indent\"/>                       \n" +
+                                            "        </xsl:if>                                                  \n" +
+                                            "      </xsl:copy>                                                  \n" +
+                                            "   </xsl:template>                                                 \n" +
+                                            "   <xsl:template match=\"comment()|processing-instruction()\">     \n" +
+                                            "      <xsl:param name=\"indent\" select=\"'&#xA;'\"/>              \n" +
+                                            "      <xsl:value-of select=\"$indent\"/>                           \n" +
+                                            "      <xsl:copy>                                                   \n" +
+                                            "        <xsl:copy-of select=\"@*\" />                              \n" +
+                                            "        <xsl:apply-templates>                                      \n" +
+                                            "          <xsl:with-param name=\"indent\"                          \n" +
+                                            "               select=\"concat($indent, $indent-increment)\"/>     \n" +
+                                            "        </xsl:apply-templates>                                     \n" +
+                                            "        <xsl:if test=\"*\">                                        \n" +
+                                            "          <xsl:value-of select=\"$indent\"/>                       \n" +
+                                            "        </xsl:if>                                                  \n" +
+                                            "      </xsl:copy>                                                  \n" +
+                                            "   </xsl:template>                                                 \n" +
+                                            "   <xsl:template match=\"text()[normalize-space(.)='']\"/>         \n" +
+                                            " </xsl:stylesheet>                                                 \n" ;
+
+    /**
+     * Method to do the transform from an XML input stream to a JSON stream.
+     * Neither input nor output streams are closed.  Closure is left up to the caller.  Same as calling toJson(inStream, outStream, false);  (Default is compact form)
+     *
+     * @param XMLStream The XML stream to convert to JSON
+     * @param JSONStream The stream to write out JSON to.  The contents written to this stream are always in UTF-8 format.
+     * 
+     * @throws SAXException Thrown is a parse error occurs.
+     * @throws IOException Thrown if an IO error occurs.
+     */
+    public static void toJson(InputStream XMLStream, OutputStream JSONStream) throws SAXException, IOException {
+        if (logger.isLoggable(Level.FINER)) {
+            logger.entering(className, "toJson(InputStream, OutputStream)");
+        }
+        toJson(XMLStream,JSONStream,false);    
+
+        if (logger.isLoggable(Level.FINER)) {
+            logger.entering(className, "toJson(InputStream, OutputStream)");
+        }
+    }
+
+    /**
+     * Method to do the transform from an XML input stream to a JSON stream.
+     * Neither input nor output streams are closed.  Closure is left up to the caller.
+     *
+     * @param XMLStream The XML stream to convert to JSON
+     * @param JSONStream The stream to write out JSON to.  The contents written to this stream are always in UTF-8 format.
+     * @param verbose Flag to denote whether or not to render the JSON text in verbose (indented easy to read), or compact (not so easy to read, but smaller), format.
+     *
+     * @throws SAXException Thrown if a parse error occurs.
+     * @throws IOException Thrown if an IO error occurs.
+     */
+    public static void toJson(InputStream XMLStream, OutputStream JSONStream, boolean verbose) throws SAXException, IOException {
+        if (logger.isLoggable(Level.FINER)) {
+            logger.entering(className, "toJson(InputStream, OutputStream)");
+        }
+
+        if (XMLStream == null) {
+            throw new NullPointerException("XMLStream cannot be null");
+        } else if (JSONStream == null) {
+            throw new NullPointerException("JSONStream cannot be null");
+        } else {
+
+            if (logger.isLoggable(Level.FINEST)) {
+                logger.logp(Level.FINEST, className, "transform", "Fetching a SAX parser for use with JSONSAXHandler");
+            }
+
+            try {
+                /**
+                 * Get a parser.
+                 */
+                SAXParserFactory factory = SAXParserFactory.newInstance();
+                factory.setNamespaceAware(true);
+                SAXParser sParser = factory.newSAXParser();
+                XMLReader parser = sParser.getXMLReader();
+                JSONSAXHandler jsonHandler = new JSONSAXHandler(JSONStream, verbose);
+                parser.setContentHandler(jsonHandler);
+                parser.setErrorHandler(jsonHandler);
+                InputSource source = new InputSource(new BufferedInputStream(XMLStream));
+
+                if (logger.isLoggable(Level.FINEST)) {
+                    logger.logp(Level.FINEST, className, "transform", "Parsing the XML content to JSON");
+                }
+
+                /** 
+                 * Parse it.
+                 */
+                source.setEncoding("UTF-8");
+                parser.parse(source);                 
+                jsonHandler.flushBuffer();
+            } catch (javax.xml.parsers.ParserConfigurationException pce) {
+                throw new SAXException("Could not get a parser: " + pce.toString());
+            }
+        }
+
+        if (logger.isLoggable(Level.FINER)) {
+            logger.exiting(className, "toJson(InputStream, OutputStream)");
+        }
+    }
+
+    /**
+     * Method to take an input stream to an XML document and return a String of the JSON format.  
+     * Note that the xmlStream is not closed when read is complete.  This is left up to the caller, who may wish to do more with it.  
+     * This is the same as toJson(xmlStream,false)
+     *
+     * @param xmlStream The InputStream to an XML document to transform to JSON.
+     * @return A string of the JSON representation of the XML file
+     * 
+     * @throws SAXException Thrown if an error occurs during parse.
+     * @throws IOException Thrown if an IOError occurs.
+     */
+    public static String toJson(InputStream xmlStream) throws SAXException, IOException {
+        return toJson(xmlStream,false);
+    }
+
+
+    /**
+     * Method to take an input stream to an XML document and return a String of the JSON format.  Note that the xmlStream is not closed when read is complete.  This is left up to the caller, who may wish to do more with it.
+     * @param xmlStream The InputStream to an XML document to transform to JSON.
+     * @param verbose Boolean flag denoting whther or not to write the JSON in verbose (formatted), or compact form (no whitespace)
+     * @return A string of the JSON representation of the XML file
+     * 
+     * @throws SAXException Thrown if an error occurs during parse.
+     * @throws IOException Thrown if an IOError occurs.
+     */                                                                    
+    public static String toJson(InputStream xmlStream, boolean verbose)  throws SAXException, IOException {
+        if (logger.isLoggable(Level.FINER)) {
+            logger.exiting(className, "toJson(InputStream, boolean)");
+        }
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        String result              = null;
+
+        try {
+            toJson(xmlStream,baos,verbose);
+            result = baos.toString("UTF-8");
+            baos.close();
+        } catch (UnsupportedEncodingException uec) {
+            IOException iox = new IOException(uec.toString());
+            iox.initCause(uec);
+            throw iox;
+        }
+
+        if (logger.isLoggable(Level.FINER)) {
+            logger.exiting(className, "toJson(InputStream, boolean)");
+        }
+
+        return result;
+    }
+
+
+    /**
+     * Method to take an XML file and return a String of the JSON format.  
+     * 
+     * @param xmlFile The XML file to transform to JSON.
+     * @param verbose Boolean flag denoting whther or not to write the JSON in verbose (formatted), or compact form (no whitespace)
+     * @return A string of the JSON representation of the XML file
+     * 
+     * @throws SAXException Thrown if an error occurs during parse.
+     * @throws IOException Thrown if an IOError occurs.
+     */
+    public static String toJson(File xmlFile, boolean verbose) throws SAXException, IOException {
+        if (logger.isLoggable(Level.FINER)) {
+            logger.exiting(className, "toJson(InputStream, boolean)");
+        }
+
+        FileInputStream fis        = new FileInputStream(xmlFile);
+        String result              = null;
+
+        result = toJson(fis,verbose);
+        fis.close();
+
+        if (logger.isLoggable(Level.FINER)) {
+            logger.exiting(className, "toJson(InputStream, boolean)");
+        }
+
+        return result;
+    }
+
+    /**
+     * Method to take an XML file and return a String of the JSON format.  
+     * This is the same as toJson(xmlStream,false)
+     *
+     * @param xmlFile The XML file to convert to JSON.
+     * @return A string of the JSON representation of the XML file
+     * 
+     * @throws SAXException Thrown if an error occurs during parse.
+     * @throws IOException Thrown if an IOError occurs.
+     */
+    public static String toJson(File xmlFile) throws SAXException, IOException {
+        return toJson(xmlFile,false);
+    }
+
+    /**
+     * Method to do the transform from an JSON input stream to a XML stream.
+     * Neither input nor output streams are closed.  Closure is left up to the caller.  Same as calling toXml(inStream, outStream, false);  (Default is compact form)
+     *
+     * @param JSONStream The JSON stream to convert to XML
+     * @param XMLStream The stream to write out XML to.  The contents written to this stream are always in UTF-8 format.
+     * 
+     * @throws IOException Thrown if an IO error occurs.
+     */
+    public static void toXml(InputStream JSONStream, OutputStream XMLStream)
+    throws IOException
+    {
+        if (logger.isLoggable(Level.FINER)) {
+            logger.entering(className, "toXml(InputStream, OutputStream)");
+        }
+        toXml(JSONStream,XMLStream,false);    
+
+        if (logger.isLoggable(Level.FINER)) {
+            logger.entering(className, "toXml(InputStream, OutputStream)");
+        }
+    }
+
+    /**
+     * Method to do the transform from an JSON input stream to a XML stream.
+     * Neither input nor output streams are closed.  Closure is left up to the caller.
+     *
+     * @param JSONStream The XML stream to convert to JSON
+     * @param XMLStream The stream to write out JSON to.  The contents written to this stream are always in UTF-8 format.
+     * @param verbose Flag to denote whether or not to render the XML text in verbose (indented easy to read), or compact (not so easy to read, but smaller), format.
+     *
+     * @throws IOException Thrown if an IO error occurs.
+     */
+    public static void toXml(InputStream JSONStream, OutputStream XMLStream, boolean verbose)
+    throws IOException
+    {
+        if (logger.isLoggable(Level.FINER)) {
+            logger.entering(className, "toXml(InputStream, OutputStream)");
+        }
+
+        if (XMLStream == null) {
+            throw new NullPointerException("XMLStream cannot be null");
+        } else if (JSONStream == null) {
+            throw new NullPointerException("JSONStream cannot be null");
+        } else {
+
+            if (logger.isLoggable(Level.FINEST)) {
+                logger.logp(Level.FINEST, className, "transform", "Parsing the JSON and a DOM builder.");
+            }
+
+            try {
+                //Get the JSON from the stream.
+                JSONObject jObject = new JSONObject(JSONStream);
+
+                //Create a new document
+
+                DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+                DocumentBuilder dBuilder = dbf.newDocumentBuilder();
+                Document doc = dBuilder.newDocument();
+
+                if (logger.isLoggable(Level.FINEST)) {
+                    logger.logp(Level.FINEST, className, "transform", "Parsing the JSON content to XML");
+                }
+
+                convertJSONObject(doc, doc.getDocumentElement(), jObject, "jsonObject");
+
+                //Serialize it.
+                TransformerFactory tfactory = TransformerFactory.newInstance();
+                Transformer serializer  = null;
+                if (verbose) {
+                    serializer = tfactory.newTransformer(new StreamSource( new StringReader(styleSheet) ));;
+                } else {
+                    serializer = tfactory.newTransformer();
+                }
+                Properties oprops = new Properties();
+                oprops.put(OutputKeys.METHOD, "xml");
+                oprops.put(OutputKeys.OMIT_XML_DECLARATION, "yes");
+                oprops.put(OutputKeys.VERSION, "1.0");
+                oprops.put(OutputKeys.INDENT, "true");
+                serializer.setOutputProperties(oprops);
+                serializer.transform(new DOMSource(doc), new StreamResult(XMLStream));
+
+            } catch (Exception ex) {
+                IOException iox = new IOException("Problem during conversion");
+                iox.initCause(ex);
+                throw iox;
+            }
+        }
+
+        if (logger.isLoggable(Level.FINER)) {
+            logger.exiting(className, "toXml(InputStream, OutputStream)");
+        }
+    }
+
+    /**
+     * Method to take an input stream to an JSON document and return a String of the XML format.  
+     * Note that the JSONStream is not closed when read is complete.  This is left up to the caller, who may wish to do more with it.  
+     * This is the same as toXml(JSONStream,false)
+     *
+     * @param JSONStream The InputStream to an JSON document to transform to XML.
+     * @return A string of the JSON representation of the XML file
+     * 
+     * @throws IOException Thrown if an IOError occurs.
+     */
+    public static String toXml(InputStream JSONStream)
+    throws IOException
+    {
+        return toXml(JSONStream,false);
+    }
+
+
+    /**
+     * Method to take an input stream to an JSON document and return a String of the XML format.  Note that the JSONStream is not closed when read is complete.  This is left up to the caller, who may wish to do more with it.
+     * @param xmlStream The InputStream to an JSON document to transform to XML.
+     * @param verbose Boolean flag denoting whther or not to write the XML in verbose (formatted), or compact form (no whitespace)
+     * @return A string of the JSON representation of the XML file
+     * 
+     * @throws IOException Thrown if an IOError occurs.
+     */
+    public static String toXml(InputStream JSONStream, boolean verbose)
+    throws IOException
+    {
+        if (logger.isLoggable(Level.FINER)) {
+            logger.exiting(className, "toXml(InputStream, boolean)");
+        }
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        String result              = null;
+
+        try {
+            toXml(JSONStream,baos,verbose);
+            result = baos.toString("UTF-8");
+            baos.close();
+        } catch (UnsupportedEncodingException uec) {
+            IOException iox = new IOException(uec.toString());
+            iox.initCause(uec);
+            throw iox;
+        }
+
+        if (logger.isLoggable(Level.FINER)) {
+            logger.exiting(className, "toXml(InputStream, boolean)");
+        }
+
+        return result;
+    }
+
+
+    /**
+     * Method to take a JSON file and return a String of the XML format.  
+     * 
+     * @param xmlFile The JSON file to transform to XML.
+     * @param verbose Boolean flag denoting whther or not to write the XML in verbose (formatted), or compact form (no whitespace)
+     * @return A string of the XML representation of the JSON file
+     * 
+     * @throws IOException Thrown if an IOError occurs.
+     */
+    public static String toXml(File jsonFile, boolean verbose)
+    throws IOException
+    {
+        if (logger.isLoggable(Level.FINER)) {
+            logger.exiting(className, "toXml(InputStream, boolean)");
+        }
+
+        FileInputStream fis        = new FileInputStream(jsonFile);
+        String result              = null;
+
+        result = toXml(fis,verbose);
+        fis.close();
+
+        if (logger.isLoggable(Level.FINER)) {
+            logger.exiting(className, "toXml(InputStream, boolean)");
+        }
+
+        return result;
+    }
+
+    /**
+     * Method to take an JSON file and return a String of the XML format.  
+     * This is the same as toXml(jsonStream,false)
+     *
+     * @param jsonFile The XML file to convert to XML.
+     * @return A string of the XML representation of the JSON file
+     * 
+     * @throws IOException Thrown if an IOError occurs.
+     */
+    public static String toXml(File jsonFile)
+    throws IOException
+    {
+        return toXml(jsonFile,false);
+    }
+
+    private static void convertJSONObject(Document doc, Element parent, JSONObject jObject, String tagName) {
+        Set attributes    = jObject.keySet();
+        Iterator attrsItr = attributes.iterator();
+
+        Element element   = doc.createElement(removeProblemCharacters(tagName));
+        if (parent != null) {
+            parent.appendChild(element);
+        } else {
+            doc.appendChild(element);
+        }
+
+        while (attrsItr.hasNext()) {
+            String attr = (String) attrsItr.next();
+            Object obj = jObject.opt(attr);
+
+            if (obj instanceof Number) {
+                element.setAttribute(attr, obj.toString());
+            } else if (obj instanceof Boolean) {
+                element.setAttribute(attr, obj.toString());
+            } else if (obj instanceof String) {
+                element.setAttribute(attr, escapeEntityCharacters(obj.toString()));
+            } else if (obj == null) {
+                element.setAttribute(attr, "");
+            } else if (obj instanceof JSONObject) {
+                convertJSONObject(doc, element, (JSONObject)obj, attr);
+            } else if (obj instanceof JSONArray) {
+                convertJSONArray(doc, element, (JSONArray)obj, attr);
+            }
+        }
+    }
+
+    private static void convertJSONArray(Document doc, Element parent, JSONArray jArray, String tagName) {
+        tagName = removeProblemCharacters(tagName);
+        for (int i = 0; i < jArray.size(); i++) {
+            Element element   = doc.createElement(tagName);
+            if (parent != null) {
+                parent.appendChild(element);
+            } else {
+                doc.appendChild(element);
+            }
+
+            Object obj = jArray.get(i);
+
+            if (obj instanceof Number) {
+                Node tNode = doc.createTextNode(obj.toString());
+                element.appendChild(tNode);
+            } else if (obj instanceof Boolean) {
+                Node tNode = doc.createTextNode(obj.toString());
+                element.appendChild(tNode);
+            } else if (obj instanceof String) {
+                Node tNode = doc.createTextNode(escapeEntityCharacters(obj.toString()));
+                element.appendChild(tNode);
+            } else if (obj instanceof JSONObject) {
+                convertJSONObject(doc, element, (JSONObject)obj, "jsonObject");
+            } else if (obj instanceof JSONArray) {
+                convertJSONArray(doc, element, (JSONArray)obj, "jsonArray");
+            }
+        }
+    }
+
+    /**
+     * Simple method to escape any special characters in the string into proper XML formatted
+     * characters.
+     * @param str The string to convert.
+     */
+    private static String escapeEntityCharacters(String str) {
+        String retVal = null;
+        if (str != null) {
+            StringBuffer strBuf = new StringBuffer("");
+            for (int i = 0; i < str.length(); i++) {
+                char character = str.charAt(i);
+
+                switch (character) {
+                    case '&':
+                        {
+                            strBuf.append("&amp;");
+                            break;
+                        }
+                    case '>':
+                        {
+                            strBuf.append("&gt;");
+                            break;
+                        }
+                    case '<':
+                        {
+                            strBuf.append("&lt;");
+                            break;
+                        }
+                    case '\"':
+                        {
+                            strBuf.append("&quot;");
+                            break;
+                        }
+                    case '\'':
+                        {
+                            strBuf.append("&apos;");
+                            break;
+                        }
+                    default:
+                        {
+                            strBuf.append(character);
+                        }
+                }
+            }
+            retVal = strBuf.toString();
+        }
+        return retVal;
+    }
+
+    /**
+     * Simple method to escape any special characters in the string into proper XML formatted
+     * characters.
+     * @param str The string to convert.
+     */
+    private static String removeProblemCharacters(String str) {
+        String retVal = null;
+        if (str != null) {
+            StringBuffer strBuf = new StringBuffer("");
+            for (int i = 0; i < str.length(); i++) {
+                char character = str.charAt(i);
+
+                switch (character) {
+                    case '&':
+                    case '>':
+                    case '<':
+                    case '\"':
+                    case '\'':
+                    case ':':
+                    case ';':
+                    case '%':
+                    case ' ':
+                    case '{':
+                    case '}':
+                    case '(':
+                    case ')':
+                    case '[':
+                    case ']':
+                    case '\\':
+                    case '/':
+                    case '|':
+                    case '#':
+                    case '*':
+                    case '^':
+                    case '!':
+                        {
+                            strBuf.append("_");
+                            break;
+                        }
+                    default:
+                        {
+                            strBuf.append(character);
+                        }
+                }
+            }
+            retVal = strBuf.toString();
+        }
+        return retVal;
+    }
+}

Added: incubator/wink/trunk/wink-json4j/src/main/java/org/apache/wink/json4j/utils/internal/JSONObject.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-json4j/src/main/java/org/apache/wink/json4j/utils/internal/JSONObject.java?rev=1021933&view=auto
==============================================================================
--- incubator/wink/trunk/wink-json4j/src/main/java/org/apache/wink/json4j/utils/internal/JSONObject.java (added)
+++ incubator/wink/trunk/wink-json4j/src/main/java/org/apache/wink/json4j/utils/internal/JSONObject.java Tue Oct 12 21:30:30 2010
@@ -0,0 +1,649 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+
+package org.apache.wink.json4j.utils.internal;
+
+import java.util.logging.*;
+import java.util.StringTokenizer;
+import java.util.Hashtable;
+import java.util.Enumeration;
+import java.util.Vector;
+import java.util.Properties;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.IOException;
+import java.io.Writer;
+
+
+/**
+ * This class is lightweight representation of an XML tag as a JSON object.
+ * TODO:  Look at using HashMap and collections to store the data instead of sync'ed objects.
+ * TODO:  See if the indent/newline handling could be cleaned up.  the repeated checks for compact is rather ugly.
+ * TODO:  Look at maybe using the Java representation object as store for the XML data intsead of this customized object.
+ */
+public class JSONObject {
+    /**
+     * Logger.
+     */
+    private static String  className              = "org.apache.commons.json.uils.xml.internal.JSONObject";
+    private static Logger logger                  = Logger.getLogger(className,null);
+    private static final String indent            = "   ";
+
+    /**
+     * The JSON object name.  Effectively, the XML tag name.
+     */
+    private String objectName     = null;
+
+    /**
+     * All basic JSON object properties.  Effectively same as XML tag attributes.
+     */
+    private Properties attrs      = null;
+
+    /**
+     * All children JSON objects referenced.  Effectively the child tags of an XML tag.
+     */
+    private Hashtable jsonObjects = null;
+
+    /**
+     * Any XML freeform text to associate with the JSON object,
+     */
+    private String tagText        = null;
+
+    /**
+     * Constructor.
+     * @param objectName The object (tag) name being constructed.
+     * @param attrs A proprerties object of all the attributes present for the tag.
+     */
+    public JSONObject(String objectName, Properties attrs) {
+        this.objectName  = objectName;
+        this.attrs       = attrs;
+        this.jsonObjects = new Hashtable();
+    }
+
+    /**
+     * Method to add a JSON child object to this JSON object.
+     * @param obj The child JSON object to add to this JSON object.
+     */
+    public void addJSONObject(JSONObject obj) {
+        if (logger.isLoggable(Level.FINER)) logger.entering(className, "addJSONObject(JSONObject)");
+
+        Vector vect = (Vector) this.jsonObjects.get(obj.objectName);
+        if (vect != null) {
+            vect.add(obj);
+        } else {
+            vect = new Vector();
+            vect.add(obj);
+            this.jsonObjects.put(obj.objectName, vect);
+        }
+
+        if (logger.isLoggable(Level.FINER)) logger.exiting(className, "addJSONObject(JSONObject)");
+    }
+
+    /**
+     * Method to set any freeform text on the object.
+     * @param str The freeform text to assign to the JSONObject
+     */
+    public void setTagText(String str) {
+        this.tagText = str;
+    }
+
+    /**
+     * Method to get any freeform text on the object.
+     */
+    public String getTagText() {
+        return this.tagText;
+    }
+
+    /**
+     * Method to write out the JSON formatted object.  Same as calling writeObject(writer,indentDepth,contentOnly,false);
+     * @param writer The writer to use when serializing the JSON structure.
+     * @param indentDepth How far to indent the text for object's JSON format.
+     * @param contentOnly Flag to debnnote whether to assign this as an attribute name, or as a nameless object.  Commonly used for serializing an array.  The Array itself has the name,   The contents are all nameless objects 
+     * @throws IOException Trhown if an error occurs on write.
+     */
+    public void writeObject(Writer writer, int indentDepth, boolean contentOnly) throws IOException {
+        if (logger.isLoggable(Level.FINER)) logger.entering(className, "writeObject(Writer, int, boolean)");
+        writeObject(writer,indentDepth,contentOnly, false);
+        if (logger.isLoggable(Level.FINER)) logger.entering(className, "writeObject(Writer, int, boolean)");
+    }
+
+
+    /**
+     * Method to write out the JSON formatted object.
+     * @param writer The writer to use when serializing the JSON structure.
+     * @param indentDepth How far to indent the text for object's JSON format.
+     * @param contentOnly Flag to debnnote whether to assign this as an attribute name, or as a nameless object.  Commonly used for serializing an array.  The Array itself has the name,   The contents are all nameless objects 
+     * @param compact Flag to denote to write the JSON in compact form.  No indentions or newlines.  Setting this value to true will cause indentDepth to be ignored.
+     * @throws IOException Trhown if an error occurs on write.
+     */
+    public void writeObject(Writer writer, int indentDepth, boolean contentOnly, boolean compact) throws IOException {
+        if (logger.isLoggable(Level.FINER)) logger.entering(className, "writeObject(Writer, int, boolean, boolean)");
+
+        if (writer != null) {
+            try {
+                if (isEmptyObject()) {
+                    writeEmptyObject(writer,indentDepth,contentOnly, compact);
+                } else if (isTextOnlyObject()) {
+                    writeTextOnlyObject(writer,indentDepth,contentOnly, compact);  
+                } else {
+                    writeComplexObject(writer,indentDepth,contentOnly,compact);
+                }
+
+            } catch (Exception ex) {
+                IOException iox = new IOException("Error occurred on serialization of JSON text.");
+                iox.initCause(ex);
+                throw iox;
+            }
+        } else {
+            throw new IOException("The writer cannot be null.");
+        }
+
+        if (logger.isLoggable(Level.FINER)) logger.entering(className, "writeObject(Writer, int, boolean, boolean)");
+    }
+
+    /**
+     * Internal method to write out a proper JSON attribute string.
+     * @param writer The writer to use while serializing
+     * @param name The attribute name to use.
+     * @param value The value to assign to the attribute.
+     * @param depth How far to indent the JSON text.
+     * @param compact Flag to denote whether or not to use pretty indention, or compact format, when writing.
+     * @throws IOException Trhown if an error occurs on write.
+     */
+    private void writeAttribute(Writer writer, String name, String value, int depth, boolean compact) throws IOException {
+        if (logger.isLoggable(Level.FINER)) logger.entering(className, "writeAttribute(Writer, String, String, int)");
+
+        if (!compact) {
+            writeIndention(writer, depth);
+        }
+
+        try {
+            if (!compact) {
+                writer.write("\"" + name + "\"" + " : " + "\"" + escapeStringSpecialCharacters(value) + "\"");
+            } else {
+                writer.write("\"" + name + "\"" + ":" + "\"" + escapeStringSpecialCharacters(value) + "\"");
+            }
+        } catch (Exception ex) {
+            IOException iox = new IOException("Error occurred on serialization of JSON text.");
+            iox.initCause(ex);
+            throw iox;
+        }
+
+        if (logger.isLoggable(Level.FINER)) logger.exiting(className, "writeAttribute(Writer, String, String, int)");
+    }
+
+    /**
+     * Internal method for doing a simple indention write.
+     * @param writer The writer to use while writing the JSON text.
+     * @param indentDepth How deep to indent the text.
+     * @throws IOException Trhown if an error occurs on write.
+     */
+    private void writeIndention(Writer writer, int indentDepth) throws IOException {
+        if (logger.isLoggable(Level.FINER)) logger.entering(className, "writeIndention(Writer, int)");
+
+        try {
+            for (int i = 0; i < indentDepth; i++) {
+                writer.write(indent);
+            }
+        } catch (Exception ex) {
+            IOException iox = new IOException("Error occurred on serialization of JSON text.");
+            iox.initCause(ex);
+            throw iox;
+        }
+
+        if (logger.isLoggable(Level.FINER)) logger.exiting(className, "writeIndention(Writer, int)");
+    }
+
+    /**
+     * Internal method to write out a proper JSON attribute string.
+     * @param writer The writer to use while serializing
+     * @param attrs The attributes in a properties object to write out
+     * @param depth How far to indent the JSON text.
+     * @param compact Whether or not to use pretty indention output, or compact output, format
+     * @throws IOException Trhown if an error occurs on write.
+     */
+    private void writeAttributes(Writer writer, Properties attrs, int depth, boolean compact) throws IOException {
+        if (logger.isLoggable(Level.FINER)) logger.entering(className, "writeAttributes(Writer, Properties, int, boolean)");
+
+        if (attrs != null) {
+            Enumeration props = attrs.propertyNames();
+
+            if (props != null && props.hasMoreElements()) {
+                while (props.hasMoreElements()) {
+                    String prop = (String)props.nextElement();
+                    writeAttribute(writer, escapeAttributeNameSpecialCharacters(prop), (String)attrs.get(prop), depth + 1, compact);
+                    if (props.hasMoreElements()) {
+                        try {
+                            if (!compact) {
+                                writer.write(",\n");
+                            } else {
+                                writer.write(",");
+                            }
+                        } catch (Exception ex) {
+                            IOException iox = new IOException("Error occurred on serialization of JSON text.");
+                            iox.initCause(ex);
+                            throw iox;
+                        }
+                    }
+                }
+            }
+        }
+
+        if (logger.isLoggable(Level.FINER)) logger.exiting(className, "writeAttributes(Writer, Properties, int, boolean)");
+    }
+
+    /**
+     * Internal method to escape special attribute name characters, to handle things like name spaces.
+     * @param str The string to escape the characters in.
+     */
+    private String escapeAttributeNameSpecialCharacters(String str) {
+        if (str != null) {
+            StringBuffer strBuf = new StringBuffer("");
+
+            for (int i = 0; i < str.length(); i++) {
+                char strChar = str.charAt(i);
+
+                switch (strChar) {
+                    case ':':
+                        {
+                            strBuf.append("_ns-sep_");
+                            break;
+                        }
+                    default:
+                        {
+                            strBuf.append(strChar);
+                            break;
+                        }
+                }
+            }
+            str = strBuf.toString();
+        }
+        return str;
+    }
+
+
+    /**
+     * Internal method to escape special attribute name characters, to handle things like name spaces.
+     * @param str The string to escape the characters in.
+     */
+    private String escapeStringSpecialCharacters(String str) {
+        if (logger.isLoggable(Level.FINER)) logger.exiting(className, "escapeStringSpecialCharacters(String)");
+
+        if (str != null) {
+            StringBuffer strBuf = new StringBuffer("");
+
+            for (int i = 0; i < str.length(); i++) {
+                char strChar = str.charAt(i);
+
+                switch (strChar) {
+                    case '"':
+                        {
+                            strBuf.append("\\\"");
+                            break;
+                        }
+                    case '\t':
+                        {
+                            strBuf.append("\\t");
+                            break;
+                        }
+                    case '\b':
+                        {
+                            strBuf.append("\\b");
+                            break;
+                        }
+                    case '\\':
+                        {
+                            strBuf.append("\\\\");
+                            break;
+                        }
+                    case '\f':
+                        {
+                            strBuf.append("\\f");
+                            break;
+                        }
+                    case '\r':
+                        {
+                            strBuf.append("\\r");
+                            break;
+                        }
+                    case '/':
+                        {
+                            strBuf.append("\\/");
+                            break;
+                        }
+                    default:
+                        {
+                            if ((strChar >= 32) && (strChar <= 126)) {
+                                strBuf.append(strChar);
+                            } else {
+                                strBuf.append("\\u");
+                                StringBuffer sb = new StringBuffer(Integer.toHexString(strChar));
+                                while (sb.length() < 4) {
+                                    sb.insert(0,'0');
+                                }
+                                strBuf.append(sb.toString());
+                            }
+
+                            break;
+                        }
+                }
+            }
+            str = strBuf.toString();
+        }
+        if (logger.isLoggable(Level.FINER)) logger.exiting(className, "escapeStringSpecialCharacters(String)");
+        return str;
+    }
+
+    /**
+     * Internal method to write out all children JSON objects attached to this JSON object.
+     * @param writer The writer to use while writing the JSON text.
+     * @param depth The indention depth of the JSON text.
+     * @param compact Flag to denote whether or not to write in nice indent format, or compact format.
+     * @throws IOException Trhown if an error occurs on write.
+     */
+    private void writeChildren(Writer writer, int depth, boolean compact) throws IOException {
+        if (logger.isLoggable(Level.FINER)) logger.entering(className, "writeChildren(Writer, int, boolean)");
+
+        if (!jsonObjects.isEmpty()) {
+            Enumeration keys = jsonObjects.keys();
+            while (keys.hasMoreElements()) {
+                String objName = (String)keys.nextElement();
+                Vector vect = (Vector)jsonObjects.get(objName);
+                if (vect != null && !vect.isEmpty()) {
+                    /**
+                     * Non-array versus array elements.
+                     */
+                    if (vect.size() == 1) {
+                        if (logger.isLoggable(Level.FINEST)) logger.logp(Level.FINEST, className, "writeChildren(Writer, int, boolean)", "Writing child object: [" + objName + "]");
+
+                        JSONObject obj = (JSONObject)vect.elementAt(0);
+                        obj.writeObject(writer,depth + 1, false, compact);
+                        if (keys.hasMoreElements()) {
+                            try {
+                                if (!compact) {
+                                    if (!obj.isTextOnlyObject() && !obj.isEmptyObject()) {
+                                        writeIndention(writer,depth + 1);
+                                    }
+                                    writer.write(",\n");
+                                } else {
+                                    writer.write(",");
+                                }
+                            } catch (Exception ex) {
+                                IOException iox = new IOException("Error occurred on serialization of JSON text.");
+                                iox.initCause(ex);
+                                throw iox;
+                            }
+                        } else {
+                            if (obj.isTextOnlyObject() && !compact) {
+                                writer.write("\n");
+                            }
+                        }
+                    } else {
+                        if (logger.isLoggable(Level.FINEST)) logger.logp(Level.FINEST, className, "writeChildren(Writer, int, boolean)", "Writing array of JSON objects with attribute name: [" + objName + "]");
+
+                        try {
+                            if (!compact) {
+                                writeIndention(writer,depth + 1);
+                                writer.write("\"" + objName + "\"");
+                                writer.write(" : [\n");
+                            } else {
+                                writer.write("\"" + objName + "\"");
+                                writer.write(":[");
+                            }
+                            for (int i = 0; i < vect.size(); i++) {
+                                JSONObject obj = (JSONObject)vect.elementAt(i);
+                                obj.writeObject(writer,depth + 2, true, compact);
+
+                                /**
+                                 * Still more we haven't handled.
+                                 */
+                                if (i != (vect.size() -1) ) {
+                                    if (!compact) {
+                                        if (!obj.isTextOnlyObject() && !obj.isEmptyObject()) {
+                                            writeIndention(writer,depth + 2);
+                                        }
+                                        writer.write(",\n");
+                                    } else {
+                                        writer.write(",");
+                                    }
+                                }
+                            }
+
+                            if (!compact) {
+                                writer.write("\n");
+                                writeIndention(writer,depth + 1);
+                            }
+
+                            writer.write("]");
+                            if (keys.hasMoreElements()) {
+                                writer.write(",");
+                            }
+
+                            if (!compact) {
+                                writer.write("\n");
+                            }
+                        } catch (Exception ex) {
+                            IOException iox = new IOException("Error occurred on serialization of JSON text.");
+                            iox.initCause(ex);
+                            throw iox;
+                        }
+                    }
+                }
+            }
+        }
+
+        if (logger.isLoggable(Level.FINER)) logger.exiting(className, "writeChildren(Writer, int, boolean)");
+    }
+
+    /**
+     * Method to write an 'empty' XML tag, like <F/>
+     * @param writer The writer object to render the XML to.
+     * @param indentDepth How far to indent.
+     * @param contentOnly Whether or not to write the object name as part of the output
+     * @param compact Flag to denote whether to output in a nice indented format, or in a compact format.
+     * @throws IOException Trhown if an error occurs on write.
+     */
+    private void writeEmptyObject(Writer writer, int indentDepth, boolean contentOnly, boolean compact) throws IOException {
+        if (logger.isLoggable(Level.FINER)) logger.entering(className, "writeEmptyObject(Writer, int, boolean, boolean)");
+
+        if (!contentOnly) {
+            if (!compact) {
+                writeIndention(writer, indentDepth);
+                writer.write("\"" + this.objectName + "\"");
+                writer.write(" : true");
+            } else {
+                writer.write("\"" + this.objectName + "\"");
+                writer.write(":true");
+            }
+
+        } else {
+            if (!compact) {
+                writeIndention(writer, indentDepth);
+                writer.write("true");
+            } else {
+                writer.write("true");
+            }
+        }
+
+        if (logger.isLoggable(Level.FINER)) logger.exiting(className, "writeEmptyObject(Writer, int, boolean, boolean)");
+    }
+
+    /**
+     * Method to write a text ony XML tagset, like <F>FOO</F>
+     * @param writer The writer object to render the XML to.
+     * @param indentDepth How far to indent.
+     * @param contentOnly Whether or not to write the object name as part of the output
+     * @param compact Whether or not to write the ohject in compact form, or nice indent form.
+     * @throws IOException Trhown if an error occurs on write.
+     */
+    private void writeTextOnlyObject(Writer writer, int indentDepth, boolean contentOnly, boolean compact) throws IOException {
+        if (logger.isLoggable(Level.FINER)) logger.entering(className, "writeTextOnlyObject(Writer, int, boolean, boolean)");
+
+        if (!contentOnly) {
+            writeAttribute(writer,this.objectName,this.tagText.trim(),indentDepth, compact);
+        } else {
+            if (!compact) {
+                writeIndention(writer, indentDepth);
+                writer.write("\"" + escapeStringSpecialCharacters(this.tagText.trim()) + "\"");
+            } else {
+                writer.write("\"" + escapeStringSpecialCharacters(this.tagText.trim()) + "\"");
+            }
+        }
+
+        if (logger.isLoggable(Level.FINER)) logger.exiting(className, "writeTextOnlyObject(Writer, int, boolean, boolean)");
+    }
+
+    /**
+     * Method to write aa standard attribute/subtag containing object
+     * @param writer The writer object to render the XML to.
+     * @param indentDepth How far to indent.
+     * @param contentOnly Whether or not to write the object name as part of the output
+     * @param compact Flag to denote whether or not to write the object in compact form.
+     * @throws IOException Trhown if an error occurs on write.
+     */
+    private void writeComplexObject(Writer writer, int indentDepth, boolean contentOnly, boolean compact) throws IOException {
+        if (logger.isLoggable(Level.FINER)) logger.entering(className, "writeComplexObject(Writer, int, boolean, boolean)");
+
+        boolean wroteTagText = false;
+
+        if (!contentOnly) {
+            if (logger.isLoggable(Level.FINEST)) logger.logp(Level.FINEST, className, "writeComplexObject(Writer, int, boolean, boolean)", "Writing object: [" + this.objectName + "]");
+
+            if (!compact) {
+                writeIndention(writer, indentDepth);
+            }
+
+            writer.write( "\"" + this.objectName + "\"");
+
+            if (!compact) {
+                writer.write(" : {\n");
+            } else {
+                writer.write(":{");
+            }
+        } else {
+            if (logger.isLoggable(Level.FINEST)) logger.logp(Level.FINEST, className, "writeObject(Writer, int, boolean, boolean)", "Writing object contents as an anonymous object (usually an array entry)");
+
+            if (!compact) {
+                writeIndention(writer, indentDepth);
+                writer.write("{\n");
+            } else {
+                writer.write("{");
+            }
+        }
+
+        if (this.tagText != null && !this.tagText.equals("") && !this.tagText.trim().equals("")) {
+            writeAttribute(writer,"content", this.tagText.trim(), indentDepth + 1, compact);
+            wroteTagText = true;
+        }
+
+        if (this.attrs != null && !this.attrs.isEmpty() && wroteTagText) {
+            if (!compact) {
+                writer.write(",\n");
+            } else {
+                writer.write(",");
+            }
+        }
+
+        writeAttributes(writer,this.attrs,indentDepth, compact);
+        if (!this.jsonObjects.isEmpty()) {
+            if (this.attrs != null && (!this.attrs.isEmpty() || wroteTagText)) {
+                if (!compact) {
+                    writer.write(",\n");
+                } else {
+                    writer.write(",");
+                }
+
+            } else {
+                if (!compact) {
+                    writer.write("\n");
+                }
+            }
+            writeChildren(writer, indentDepth, compact);
+        } else {
+            if (!compact) {
+                writer.write("\n");
+            }
+        }
+
+        if (!compact) {
+            writeIndention(writer, indentDepth);
+            writer.write("}\n");
+            //writer.write("\n");
+        } else {
+            writer.write("}");
+        }
+
+        if (logger.isLoggable(Level.FINER)) logger.exiting(className, "writeComplexObject(Writer, int, boolean, boolean)");
+    }
+
+
+    /**
+     * Internal Helper method for determining if this is an empty tag inan XML document, such as <F/>
+     * @return boolean denoting whether or not the object being written contains any attributes, tags, or text.
+     */
+    private boolean isEmptyObject() {
+        boolean retVal = false;
+
+        /**
+         * Check for no attributes
+         */
+        if (this.attrs == null || (this.attrs != null && this.attrs.isEmpty())) {
+            /**
+             * Check for no sub-children
+             */
+            if (this.jsonObjects.isEmpty()) {
+                /**
+                 * Check for no tag text.
+                 */
+                if (this.tagText == null || (this.tagText != null && this.tagText.trim().equals(""))) {
+                    retVal = true;
+                }
+            }
+        }
+
+        return retVal;
+    }
+
+    /**
+     * Internal Helper method for determining if this is an XML tag which contains only freeform text, like: <F>foo</F>
+     * @return boolean denoting whether or not the object being written is a text-only XML tagset.
+     */
+    private boolean isTextOnlyObject() {
+        boolean retVal = false;
+
+        /**
+         * Check for no attributes
+         */
+        if (this.attrs == null || (this.attrs != null && this.attrs.isEmpty())) {
+            /**
+             * Check for no sub-children
+             */
+            if (this.jsonObjects.isEmpty()) {
+                /**
+                 * Check for tag text contents.
+                 */
+                if (this.tagText != null && !this.tagText.trim().equals("")) {
+                    retVal = true;
+                }
+            }
+        }
+
+        return retVal;
+    }
+}

Added: incubator/wink/trunk/wink-json4j/src/main/java/org/apache/wink/json4j/utils/internal/JSONSAXHandler.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-json4j/src/main/java/org/apache/wink/json4j/utils/internal/JSONSAXHandler.java?rev=1021933&view=auto
==============================================================================
--- incubator/wink/trunk/wink-json4j/src/main/java/org/apache/wink/json4j/utils/internal/JSONSAXHandler.java (added)
+++ incubator/wink/trunk/wink-json4j/src/main/java/org/apache/wink/json4j/utils/internal/JSONSAXHandler.java Tue Oct 12 21:30:30 2010
@@ -0,0 +1,222 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+
+package org.apache.wink.json4j.utils.internal;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+import java.util.logging.*;
+import java.util.Stack;
+import java.util.StringTokenizer;
+import java.util.Properties;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.IOException;
+
+
+/**
+ * This class is a SAX entension to do conversion of XML to JSON.
+ */
+public class JSONSAXHandler extends DefaultHandler {
+    /**
+     * Logger code
+     */
+    private static String  className              = "org.apache.commons.json.utils.xml.transform.impl.JSONSAXHandler";
+    private static Logger logger                  = Logger.getLogger(className,null);
+
+    /**
+     * The writer to stream the JSON text out to.
+     */
+    private OutputStreamWriter osWriter           = null;
+
+    /**
+     * The current JSON object being constructed from the current TAG being parsed.
+     */
+    private JSONObject current                    = null;
+
+    /** 
+     * The stack of the current JSON object position.
+     */
+    private Stack previousObjects                 = new Stack();
+
+    /**
+     * The toplevel containing JSON object.
+     */
+    private JSONObject head                       = null;
+
+    /**
+     * Whether or not to render the JSON text is a compact or indented format.
+     */
+    private boolean compact                       = false;
+
+    /**
+     * Constructor.
+     * @param os The outputStream to write the resulting JSON to.  Same as JSONSAXHander(os,false);
+     * @throws IOException Thrown if an error occurs during streaming out, or XML read.
+     */
+    public JSONSAXHandler(OutputStream os) throws IOException {
+        if (logger.isLoggable(Level.FINER)) logger.entering(className, "JSONHander(OutputStream) <constructor>");
+
+        this.osWriter = new OutputStreamWriter(os,"UTF-8");
+        this.compact  = true;
+
+        if (logger.isLoggable(Level.FINER)) logger.exiting(className, "JSONHander(OutputStream) <constructor>");
+    }
+
+    /**
+     * Constructor.
+     * @param os The outputStream to write the resulting JSON to
+     * @param verbose Whenther or not to render the stream in a verbose (formatted), or compact form.
+     * @throws IOException Thrown if an error occurs during streaming out, or XML read.
+     */
+    public JSONSAXHandler(OutputStream os, boolean verbose) throws IOException {
+        if (logger.isLoggable(Level.FINER)) logger.entering(className, "JSONHander(OutputStream, boolean) <constructor>");
+
+        this.osWriter = new OutputStreamWriter(os,"UTF-8");
+        this.compact  = !verbose;
+
+        if (logger.isLoggable(Level.FINER)) logger.exiting(className, "JSONHander(OutputStream, boolean) <constructor>");
+    }
+
+
+    /**
+     * This function parses an IFix top level element and all its children.
+     */
+    public void startElement(String namespaceURI, String localName, String qName, Attributes attrs) throws SAXException {
+        if (logger.isLoggable(Level.FINER)) logger.exiting(className, "startElement(String,String,String,org.xml.sax.Attributes)");
+
+        Properties props = new Properties();
+        int attrLength = attrs.getLength();
+        for (int i = 0; i < attrLength; i++) {
+            props.put(attrs.getQName(i), attrs.getValue(i));
+        }
+
+        JSONObject obj = new JSONObject(localName, props);
+        if (this.head == null) {
+            this.head    = obj;
+            this.current = head;
+        } else {
+            if (current != null) {
+                this.previousObjects.push(current);
+                this.current.addJSONObject(obj);
+            }
+            this.current  = obj;
+        }
+
+        if (logger.isLoggable(Level.FINER)) logger.exiting(className, "startElement(String,String,String,org.xml.sax.Attributes)");
+    }
+
+    /**
+     * Function ends a tag in this iFix parser.
+     */
+    public void endElement(String uri, String localName, String qName) throws SAXException {
+        if (logger.isLoggable(Level.FINER)) logger.entering(className, "endElement(String,String,String)");
+
+        if (!previousObjects.isEmpty()) {
+            this.current = (JSONObject)this.previousObjects.pop();
+        } else {
+            this.current = null;
+        }
+
+        if (logger.isLoggable(Level.FINER)) logger.exiting(className, "endElement(String,String,String)");
+    }
+
+    public void characters(char[] ch,
+                           int start,
+                           int length)
+    throws SAXException {
+        if (logger.isLoggable(Level.FINER)) logger.entering(className, "characters(char[], int, int)");
+
+        String str = new String(ch,start,length);
+        if (this.current.getTagText() != null) {
+            str = this.current.getTagText() + str;
+        }
+        this.current.setTagText(str);
+
+        if (logger.isLoggable(Level.FINER)) logger.exiting(className, "characters(char[], int, int)");
+    }
+
+    public void startDocument() throws SAXException {
+        if (logger.isLoggable(Level.FINER)) logger.entering(className, "startDocument()");
+
+        startJSON();
+
+        if (logger.isLoggable(Level.FINER)) logger.exiting(className, "startDocument()");
+    }
+
+    public void endDocument() throws SAXException {
+        if (logger.isLoggable(Level.FINER)) logger.exiting(className, "endDocument()");
+
+        endJSON();
+
+        if (logger.isLoggable(Level.FINER)) logger.exiting(className, "endDocument()");
+    }
+
+    /**
+     * Method to flush out anything remaining in the buffers.
+     */
+    public void flushBuffer() throws IOException {
+        if (logger.isLoggable(Level.FINER)) logger.entering(className, "flushBuffer()");
+
+        if (this.osWriter != null) {
+            this.osWriter.flush();
+        }
+
+        if (logger.isLoggable(Level.FINER)) logger.exiting(className, "flushBuffer()");
+    }
+
+    /**
+     * Internal method to start JSON generation.
+     */
+    private void startJSON() throws SAXException {
+        if (logger.isLoggable(Level.FINER)) logger.entering(className, "startJSON()");
+
+        this.head    = new JSONObject("",null);
+        this.current = head;
+
+        if (logger.isLoggable(Level.FINER)) logger.exiting(className, "startJSON()");
+    }
+
+    /**
+     * Internal method to end the JSON generation and to write out the resultant JSON text 
+     * and reset the internal state of the hander.
+     */
+    private void endJSON() throws SAXException {   
+        if (logger.isLoggable(Level.FINER)) logger.entering(className, "endJSON()");
+
+        try {
+            this.head.writeObject(this.osWriter, 0, true, this.compact);
+            this.head    = null;
+            this.current = null;
+            this.previousObjects.clear();
+        } catch (Exception ex) {
+            SAXException saxEx = new SAXException(ex);
+            saxEx.initCause(ex);
+            throw saxEx;
+        }
+
+        if (logger.isLoggable(Level.FINER)) logger.exiting(className, "endJSON()");
+    }
+
+}
+
+



Mime
View raw message