Coverage Report - net.sf.json.xml.XMLSerializer
 
Classes in this File Line Coverage Branch Coverage Complexity
XMLSerializer
0%
0/616
0%
0/444
4.154
XMLSerializer$CustomElement
0%
0/14
0%
0/6
4.154
XMLSerializer$XomSerializer
0%
0/39
0%
0/18
4.154
 
 1  
 /*
 2  
  * Copyright 2002-2009 the original author or authors.
 3  
  *
 4  
  * Licensed under the Apache License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  *      http://www.apache.org/licenses/LICENSE-2.0
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 
 17  
 package net.sf.json.xml;
 18  
 
 19  
 import java.io.BufferedReader;
 20  
 import java.io.ByteArrayOutputStream;
 21  
 import java.io.File;
 22  
 import java.io.FileInputStream;
 23  
 import java.io.IOException;
 24  
 import java.io.InputStream;
 25  
 import java.io.InputStreamReader;
 26  
 import java.io.OutputStream;
 27  
 import java.io.StringReader;
 28  
 import java.io.UnsupportedEncodingException;
 29  
 import java.util.Arrays;
 30  
 import java.util.Iterator;
 31  
 import java.util.Map;
 32  
 import java.util.TreeMap;
 33  
 
 34  
 import net.sf.json.JSON;
 35  
 import net.sf.json.JSONArray;
 36  
 import net.sf.json.JSONException;
 37  
 import net.sf.json.JSONFunction;
 38  
 import net.sf.json.JSONNull;
 39  
 import net.sf.json.JSONObject;
 40  
 import net.sf.json.util.JSONUtils;
 41  
 import nu.xom.Attribute;
 42  
 import nu.xom.Builder;
 43  
 import nu.xom.Document;
 44  
 import nu.xom.Element;
 45  
 import nu.xom.Elements;
 46  
 import nu.xom.Node;
 47  
 import nu.xom.Serializer;
 48  
 import nu.xom.Text;
 49  
 
 50  
 import org.apache.commons.lang.ArrayUtils;
 51  
 import org.apache.commons.lang.StringUtils;
 52  
 import org.apache.commons.logging.Log;
 53  
 import org.apache.commons.logging.LogFactory;
 54  
 
 55  
 /**
 56  
  * Utility class for transforming JSON to XML an back.<br>
 57  
  * When transforming JSONObject and JSONArray instances to XML, this class will
 58  
  * add hints for converting back to JSON.<br>
 59  
  * Examples:<br>
 60  
  *
 61  
  * <pre>
 62  
  * JSONObject json = JSONObject.fromObject("{\"name\":\"json\",\"bool\":true,\"int\":1}");
 63  
  * String xml = new XMLSerializer().write( json );
 64  
  * <xmp><o class="object">
 65  
  <name type="string">json</name>
 66  
  <bool type="boolean">true</bool>
 67  
  <int type="number">1</int>
 68  
  </o></xmp>
 69  
  * </pre><pre>
 70  
  * JSONArray json = JSONArray.fromObject("[1,2,3]");
 71  
  * String xml = new XMLSerializer().write( json );
 72  
  * <xmp><a class="array">
 73  
  <e type="number">1</e>
 74  
  <e type="number">2</e>
 75  
  <e type="number">3</e>
 76  
  </a></xmp>
 77  
  * </pre>
 78  
  *
 79  
  * @author Andres Almiray <aalmiray@users.sourceforge.net>
 80  
  */
 81  
 public class XMLSerializer {
 82  0
    private static final String[] EMPTY_ARRAY = new String[0];
 83  
    private static final String JSON_PREFIX = "json_";
 84  0
    private static final Log log = LogFactory.getLog( XMLSerializer.class );
 85  
 
 86  
    /** the name for an JSONArray Element */
 87  
    private String arrayName;
 88  
    /** the name for an JSONArray's element Element */
 89  
    private String elementName;
 90  
    /** list of properties to be expanded from child to parent */
 91  
    private String[] expandableProperties;
 92  
    private boolean forceTopLevelObject;
 93  
    /** flag to be tolerant for incomplete namespace prefixes */
 94  
    private boolean namespaceLenient;
 95  
    /** Map of namespaces per element */
 96  0
    private Map namespacesPerElement = new TreeMap();
 97  
    /** the name for an JSONObject Element */
 98  
    private String objectName;
 99  
    /** flag for trimming namespace prefix from element name */
 100  
    private boolean removeNamespacePrefixFromElements;
 101  
    /** the name for the root Element */
 102  
    private String rootName;
 103  
    /** Map of namespaces for root element */
 104  0
    private Map rootNamespace = new TreeMap();
 105  
    /** flag for skipping namespaces while reading */
 106  
    private boolean skipNamespaces;
 107  
    /** flag for skipping whitespace elements while reading */
 108  
    private boolean skipWhitespace;
 109  
    /** flag for trimming spaces from string values */
 110  
    private boolean trimSpaces;
 111  
    /** flag for type hints naming compatibility */
 112  
    private boolean typeHintsCompatibility;
 113  
    /** flag for adding JSON types hints as attributes */
 114  
    private boolean typeHintsEnabled;
 115  
 
 116  
    /**
 117  
     * Creates a new XMLSerializer with default options.<br>
 118  
     * <ul>
 119  
     * <li><code>objectName</code>: 'o'</li>
 120  
     * <li><code>arrayName</code>: 'a'</li>
 121  
     * <li><code>elementName</code>: 'e'</li>
 122  
     * <li><code>typeHinstEnabled</code>: true</li>
 123  
     * <li><code>typeHinstCompatibility</code>: true</li>
 124  
     * <li><code>namespaceLenient</code>: false</li>
 125  
     * <li><code>expandableProperties</code>: []</li>
 126  
     * <li><code>skipNamespaces</code>: false</li>
 127  
     * <li><code>removeNameSpacePrefixFromElement</code>: false</li>
 128  
     * <li><code>trimSpaces</code>: false</li>
 129  
     * </ul>
 130  
     */
 131  0
    public XMLSerializer() {
 132  0
       setObjectName( "o" );
 133  0
       setArrayName( "a" );
 134  0
       setElementName( "e" );
 135  0
       setTypeHintsEnabled( true );
 136  0
       setTypeHintsCompatibility( true );
 137  0
       setNamespaceLenient( false );
 138  0
       setSkipNamespaces( false );
 139  0
       setRemoveNamespacePrefixFromElements( false );
 140  0
       setTrimSpaces( false );
 141  0
       setExpandableProperties( EMPTY_ARRAY );
 142  0
       setSkipNamespaces( false );
 143  0
    }
 144  
 
 145  
    /**
 146  
     * Adds a namespace declaration to the root element.
 147  
     *
 148  
     * @param prefix namespace prefix
 149  
     * @param uri namespace uri
 150  
     */
 151  
    public void addNamespace( String prefix, String uri ) {
 152  0
       addNamespace( prefix, uri, null );
 153  0
    }
 154  
 
 155  
    /**
 156  
     * Adds a namespace declaration to an element.<br>
 157  
     * If the elementName param is null or blank, the namespace declaration will
 158  
     * be added to the root element.
 159  
     *
 160  
     * @param prefix namespace prefix
 161  
     * @param uri namespace uri
 162  
     * @param elementName name of target element
 163  
     */
 164  
    public void addNamespace( String prefix, String uri, String elementName ) {
 165  0
       if( StringUtils.isBlank( uri ) ){
 166  0
          return;
 167  
       }
 168  0
       if( prefix == null ){
 169  0
          prefix = "";
 170  
       }
 171  0
       if( StringUtils.isBlank( elementName ) ){
 172  0
          rootNamespace.put( prefix.trim(), uri.trim() );
 173  
       }else{
 174  0
          Map nameSpaces = (Map) namespacesPerElement.get( elementName );
 175  0
          if( nameSpaces == null ){
 176  0
             nameSpaces = new TreeMap();
 177  0
             namespacesPerElement.put( elementName, nameSpaces );
 178  
          }
 179  0
          nameSpaces.put( prefix, uri );
 180  
       }
 181  0
    }
 182  
 
 183  
    /**
 184  
     * Removes all namespaces declarations (from root an elements).
 185  
     */
 186  
    public void clearNamespaces() {
 187  0
       rootNamespace.clear();
 188  0
       namespacesPerElement.clear();
 189  0
    }
 190  
 
 191  
    /**
 192  
     * Removes all namespace declarations from an element.<br>
 193  
     * If the elementName param is null or blank, the declarations will be
 194  
     * removed from the root element.
 195  
     *
 196  
     * @param elementName name of target element
 197  
     */
 198  
    public void clearNamespaces( String elementName ) {
 199  0
       if( StringUtils.isBlank( elementName ) ){
 200  0
          rootNamespace.clear();
 201  
       }else{
 202  0
          namespacesPerElement.remove( elementName );
 203  
       }
 204  0
    }
 205  
 
 206  
    /**
 207  
     * Returns the name used for JSONArray.
 208  
     */
 209  
    public String getArrayName() {
 210  0
       return arrayName;
 211  
    }
 212  
 
 213  
    /**
 214  
     * Returns the name used for JSONArray elements.
 215  
     */
 216  
    public String getElementName() {
 217  0
       return elementName;
 218  
    }
 219  
 
 220  
    /**
 221  
     * Returns a list of properties to be expanded from child to parent.
 222  
     */
 223  
    public String[] getExpandableProperties() {
 224  0
       return expandableProperties;
 225  
    }
 226  
 
 227  
    /**
 228  
     * Returns the name used for JSONArray.
 229  
     */
 230  
    public String getObjectName() {
 231  0
       return objectName;
 232  
    }
 233  
 
 234  
    /**
 235  
     * Returns the name used for the root element.
 236  
     */
 237  
    public String getRootName() {
 238  0
       return rootName;
 239  
    }
 240  
 
 241  
    public boolean isForceTopLevelObject() {
 242  0
       return forceTopLevelObject;
 243  
    }
 244  
 
 245  
    /**
 246  
     * Returns wether this serializer is tolerant to namespaces without URIs or
 247  
     * not.
 248  
     */
 249  
    public boolean isNamespaceLenient() {
 250  0
       return namespaceLenient;
 251  
    }
 252  
 
 253  
    /**
 254  
     * Returns wether this serializer will remove namespace prefix from elements
 255  
     * or not.
 256  
     */
 257  
    public boolean isRemoveNamespacePrefixFromElements() {
 258  0
       return removeNamespacePrefixFromElements;
 259  
    }
 260  
 
 261  
    /**
 262  
     * Returns wether this serializer will skip adding namespace declarations to
 263  
     * elements or not.
 264  
     */
 265  
    public boolean isSkipNamespaces() {
 266  0
       return skipNamespaces;
 267  
    }
 268  
 
 269  
    /**
 270  
     * Returns wether this serializer will skip whitespace or not.
 271  
     */
 272  
    public boolean isSkipWhitespace() {
 273  0
       return skipWhitespace;
 274  
    }
 275  
 
 276  
    /**
 277  
     * Returns wether this serializer will trim leading and trealing whitespace
 278  
     * from values or not.
 279  
     */
 280  
    public boolean isTrimSpaces() {
 281  0
       return trimSpaces;
 282  
    }
 283  
 
 284  
    /**
 285  
     * Returns true if types hints will have a 'json_' prefix or not.
 286  
     */
 287  
    public boolean isTypeHintsCompatibility() {
 288  0
       return typeHintsCompatibility;
 289  
    }
 290  
 
 291  
    /**
 292  
     * Returns true if JSON types will be included as attributes.
 293  
     */
 294  
    public boolean isTypeHintsEnabled() {
 295  0
       return typeHintsEnabled;
 296  
    }
 297  
 
 298  
    /**
 299  
     * Creates a JSON value from a XML string.
 300  
     *
 301  
     * @param xml A well-formed xml document in a String
 302  
     * @return a JSONNull, JSONObject or JSONArray
 303  
     * @throws JSONException if the conversion from XML to JSON can't be made for
 304  
     *         I/O or format reasons.
 305  
     */
 306  
    public JSON read( String xml ) {
 307  0
       JSON json = null;
 308  
       try{
 309  0
          Document doc = new Builder().build( new StringReader( xml ) );
 310  0
          Element root = doc.getRootElement();
 311  0
          if( isNullObject( root ) ){
 312  0
             return JSONNull.getInstance();
 313  
          }
 314  0
          String defaultType = getType( root, JSONTypes.STRING );
 315  0
          if( isArray( root, true ) ){
 316  0
             json = processArrayElement( root, defaultType );
 317  0
             if( forceTopLevelObject ){
 318  0
                String key = removeNamespacePrefix( root.getQualifiedName() );
 319  0
                json = new JSONObject().element( key, json );
 320  0
             }
 321  
          }else{ 
 322  0
             json = processObjectElement( root, defaultType );
 323  0
             if( forceTopLevelObject ) {
 324  0
                String key = removeNamespacePrefix( root.getQualifiedName() );
 325  0
                json = new JSONObject().element( key, json );
 326  
             }
 327  
          }
 328  0
       }catch( JSONException jsone ){
 329  0
          throw jsone;
 330  0
       }catch( Exception e ){
 331  0
          throw new JSONException( e );
 332  0
       }
 333  0
       return json;
 334  
    }
 335  
 
 336  
    /**
 337  
     * Creates a JSON value from a File.
 338  
     *
 339  
     * @param file
 340  
     * @return a JSONNull, JSONObject or JSONArray
 341  
     * @throws JSONException if the conversion from XML to JSON can't be made for
 342  
     *         I/O or format reasons.
 343  
     */
 344  
    public JSON readFromFile( File file ) {
 345  0
       if( file == null ){
 346  0
          throw new JSONException( "File is null" );
 347  
       }
 348  0
       if( !file.canRead() ){
 349  0
          throw new JSONException( "Can't read input file" );
 350  
       }
 351  0
       if( file.isDirectory() ){
 352  0
          throw new JSONException( "File is a directory" );
 353  
       }
 354  
       try{
 355  0
          return readFromStream( new FileInputStream( file ) );
 356  0
       }catch( IOException ioe ){
 357  0
          throw new JSONException( ioe );
 358  
       }
 359  
    }
 360  
 
 361  
    /**
 362  
     * Creates a JSON value from a File.
 363  
     *
 364  
     * @param path
 365  
     * @return a JSONNull, JSONObject or JSONArray
 366  
     * @throws JSONException if the conversion from XML to JSON can't be made for
 367  
     *         I/O or format reasons.
 368  
     */
 369  
    public JSON readFromFile( String path ) {
 370  0
       return readFromStream( Thread.currentThread()
 371  
             .getContextClassLoader()
 372  
             .getResourceAsStream( path ) );
 373  
    }
 374  
 
 375  
    /**
 376  
     * Creates a JSON value from an input stream.
 377  
     *
 378  
     * @param stream
 379  
     * @return a JSONNull, JSONObject or JSONArray
 380  
     * @throws JSONException if the conversion from XML to JSON can't be made for
 381  
     *         I/O or format reasons.
 382  
     */
 383  
    public JSON readFromStream( InputStream stream ) {
 384  
       try{
 385  0
          StringBuffer xml = new StringBuffer();
 386  0
          BufferedReader in = new BufferedReader( new InputStreamReader( stream ) );
 387  0
          String line = null;
 388  0
          while( (line = in.readLine()) != null ){
 389  0
             xml.append( line );
 390  
          }
 391  0
          return read( xml.toString() );
 392  0
       }catch( IOException ioe ){
 393  0
          throw new JSONException( ioe );
 394  
       }
 395  
    }
 396  
 
 397  
    /**
 398  
     * Removes a namespace from the root element.
 399  
     *
 400  
     * @param prefix namespace prefix
 401  
     */
 402  
    public void removeNamespace( String prefix ) {
 403  0
       removeNamespace( prefix, null );
 404  0
    }
 405  
 
 406  
    /**
 407  
     * Removes a namespace from the root element.<br>
 408  
     * If the elementName is null or blank, the namespace will be removed from
 409  
     * the root element.
 410  
     *
 411  
     * @param prefix namespace prefix
 412  
     * @param elementName name of target element
 413  
     */
 414  
    public void removeNamespace( String prefix, String elementName ) {
 415  0
       if( prefix == null ){
 416  0
          prefix = "";
 417  
       }
 418  0
       if( StringUtils.isBlank( elementName ) ){
 419  0
          rootNamespace.remove( prefix.trim() );
 420  
       }else{
 421  0
          Map nameSpaces = (Map) namespacesPerElement.get( elementName );
 422  0
          nameSpaces.remove( prefix );
 423  
       }
 424  0
    }
 425  
 
 426  
    /**
 427  
     * Sets the name used for JSONArray.<br>
 428  
     * Default is 'a'.
 429  
     */
 430  
    public void setArrayName( String arrayName ) {
 431  0
       this.arrayName = StringUtils.isBlank( arrayName ) ? "a" : arrayName;
 432  0
    }
 433  
 
 434  
    /**
 435  
     * Sets the name used for JSONArray elements.<br>
 436  
     * Default is 'e'.
 437  
     */
 438  
    public void setElementName( String elementName ) {
 439  0
       this.elementName = StringUtils.isBlank( elementName ) ? "e" : elementName;
 440  0
    }
 441  
 
 442  
    /**
 443  
     * Sets the list of properties to be expanded from child to parent.
 444  
     */
 445  
    public void setExpandableProperties( String[] expandableProperties ) {
 446  0
       this.expandableProperties = expandableProperties == null ? EMPTY_ARRAY : expandableProperties;
 447  0
    }
 448  
 
 449  
    public void setForceTopLevelObject( boolean forceTopLevelObject ) {
 450  0
       this.forceTopLevelObject = forceTopLevelObject;
 451  0
    }
 452  
 
 453  
    /**
 454  
     * Sets the namespace declaration to the root element.<br>
 455  
     * Any previous values are discarded.
 456  
     *
 457  
     * @param prefix namespace prefix
 458  
     * @param uri namespace uri
 459  
     */
 460  
    public void setNamespace( String prefix, String uri ) {
 461  0
       setNamespace( prefix, uri, null );
 462  0
    }
 463  
 
 464  
    /**
 465  
     * Adds a namespace declaration to an element.<br>
 466  
     * Any previous values are discarded. If the elementName param is null or
 467  
     * blank, the namespace declaration will be added to the root element.
 468  
     *
 469  
     * @param prefix namespace prefix
 470  
     * @param uri namespace uri
 471  
     * @param elementName name of target element
 472  
     */
 473  
    public void setNamespace( String prefix, String uri, String elementName ) {
 474  0
       if( StringUtils.isBlank( uri ) ){
 475  0
          return;
 476  
       }
 477  0
       if( prefix == null ){
 478  0
          prefix = "";
 479  
       }
 480  0
       if( StringUtils.isBlank( elementName ) ){
 481  0
          rootNamespace.clear();
 482  0
          rootNamespace.put( prefix.trim(), uri.trim() );
 483  
       }else{
 484  0
          Map nameSpaces = (Map) namespacesPerElement.get( elementName );
 485  0
          if( nameSpaces == null ){
 486  0
             nameSpaces = new TreeMap();
 487  0
             namespacesPerElement.put( elementName, nameSpaces );
 488  
          }
 489  0
          nameSpaces.clear();
 490  0
          nameSpaces.put( prefix, uri );
 491  
       }
 492  0
    }
 493  
 
 494  
    /**
 495  
     * Sets wether this serializer is tolerant to namespaces without URIs or not.
 496  
     */
 497  
    public void setNamespaceLenient( boolean namespaceLenient ) {
 498  0
       this.namespaceLenient = namespaceLenient;
 499  0
    }
 500  
 
 501  
    /**
 502  
     * Sets the name used for JSONObject.<br>
 503  
     * Default is 'o'.
 504  
     */
 505  
    public void setObjectName( String objectName ) {
 506  0
       this.objectName = StringUtils.isBlank( objectName ) ? "o" : objectName;
 507  0
    }
 508  
 
 509  
    /**
 510  
     * Sets if this serializer will remove namespace prefix from elements when
 511  
     * reading.
 512  
     */
 513  
    public void setRemoveNamespacePrefixFromElements( boolean removeNamespacePrefixFromElements ) {
 514  0
       this.removeNamespacePrefixFromElements = removeNamespacePrefixFromElements;
 515  0
    }
 516  
 
 517  
    /**
 518  
     * Sets the name used for the root element.
 519  
     */
 520  
    public void setRootName( String rootName ) {
 521  0
       this.rootName = StringUtils.isBlank( rootName ) ? null : rootName;
 522  0
    }
 523  
 
 524  
    /**
 525  
     * Sets if this serializer will skip adding namespace declarations to
 526  
     * elements when reading.
 527  
     */
 528  
    public void setSkipNamespaces( boolean skipNamespaces ) {
 529  0
       this.skipNamespaces = skipNamespaces;
 530  0
    }
 531  
 
 532  
    /**
 533  
     * Sets if this serializer will skip whitespace when reading.
 534  
     */
 535  
    public void setSkipWhitespace( boolean skipWhitespace ) {
 536  0
       this.skipWhitespace = skipWhitespace;
 537  0
    }
 538  
 
 539  
    /**
 540  
     * Sets if this serializer will trim leading and trealing whitespace from
 541  
     * values when reading.
 542  
     */
 543  
    public void setTrimSpaces( boolean trimSpaces ) {
 544  0
       this.trimSpaces = trimSpaces;
 545  0
    }
 546  
 
 547  
    /**
 548  
     * Sets wether types hints will have a 'json_' prefix or not.
 549  
     */
 550  
    public void setTypeHintsCompatibility( boolean typeHintsCompatibility ) {
 551  0
       this.typeHintsCompatibility = typeHintsCompatibility;
 552  0
    }
 553  
 
 554  
    /**
 555  
     * Sets wether JSON types will be included as attributes.
 556  
     */
 557  
    public void setTypeHintsEnabled( boolean typeHintsEnabled ) {
 558  0
       this.typeHintsEnabled = typeHintsEnabled;
 559  0
    }
 560  
 
 561  
    /**
 562  
     * Writes a JSON value into a XML string with UTF-8 encoding.<br>
 563  
     *
 564  
     * @param json The JSON value to transform
 565  
     * @return a String representation of a well-formed xml document.
 566  
     * @throws JSONException if the conversion from JSON to XML can't be made for
 567  
     *         I/O reasons.
 568  
     */
 569  
    public String write( JSON json ) {
 570  0
       return write( json, null );
 571  
    }
 572  
 
 573  
    /**
 574  
     * Writes a JSON value into a XML string with an specific encoding.<br>
 575  
     * If the encoding string is null it will use UTF-8.
 576  
     *
 577  
     * @param json The JSON value to transform
 578  
     * @param encoding The xml encoding to use
 579  
     * @return a String representation of a well-formed xml document.
 580  
     * @throws JSONException if the conversion from JSON to XML can't be made for
 581  
     *         I/O reasons or the encoding is not supported.
 582  
     */
 583  
    public String write( JSON json, String encoding ) {
 584  0
       if( JSONNull.getInstance()
 585  
             .equals( json ) ){
 586  0
          Element root = null;
 587  0
          root = newElement( getRootName() == null ? getObjectName() : getRootName() );
 588  0
          root.addAttribute( new Attribute( addJsonPrefix( "null" ), "true" ) );
 589  0
          Document doc = new Document( root );
 590  0
          return writeDocument( doc, encoding );
 591  0
       }else if( json instanceof JSONArray ){
 592  0
          JSONArray jsonArray = (JSONArray) json;
 593  0
          Element root = processJSONArray( jsonArray,
 594  
                newElement( getRootName() == null ? getArrayName() : getRootName() ),
 595  
                expandableProperties );
 596  0
          Document doc = new Document( root );
 597  0
          return writeDocument( doc, encoding );
 598  
       }else{
 599  0
          JSONObject jsonObject = (JSONObject) json;
 600  0
          Element root = null;
 601  0
          if( jsonObject.isNullObject() ){
 602  0
             root = newElement( getObjectName() );
 603  0
             root.addAttribute( new Attribute( addJsonPrefix( "null" ), "true" ) );
 604  
          }else{
 605  0
             root = processJSONObject( jsonObject,
 606  
                   newElement( getRootName() == null ? getObjectName() : getRootName() ),
 607  
                   expandableProperties, true );
 608  
          }
 609  0
          Document doc = new Document( root );
 610  0
          return writeDocument( doc, encoding );
 611  
       }
 612  
    }
 613  
 
 614  
    private String addJsonPrefix( String str ) {
 615  0
       if( !isTypeHintsCompatibility() ){
 616  0
          return JSON_PREFIX + str;
 617  
       }
 618  0
       return str;
 619  
    }
 620  
 
 621  
    private void addNameSpaceToElement( Element element ) {
 622  0
       String elementName = null;
 623  0
       if( element instanceof CustomElement ){
 624  0
          elementName = ((CustomElement) element).getQName();
 625  
       }else{
 626  0
          elementName = element.getQualifiedName();
 627  
       }
 628  0
       Map nameSpaces = (Map) namespacesPerElement.get( elementName );
 629  0
       if( nameSpaces != null && !nameSpaces.isEmpty() ){
 630  0
          setNamespaceLenient( true );
 631  0
          for( Iterator entries = nameSpaces.entrySet()
 632  0
                .iterator(); entries.hasNext(); ){
 633  0
             Map.Entry entry = (Map.Entry) entries.next();
 634  0
             String prefix = (String) entry.getKey();
 635  0
             String uri = (String) entry.getValue();
 636  0
             if( StringUtils.isBlank( prefix ) ){
 637  0
                element.setNamespaceURI( uri );
 638  
             }else{
 639  0
                element.addNamespaceDeclaration( prefix, uri );
 640  
             }
 641  0
          }
 642  
       }
 643  0
    }
 644  
 
 645  
    private boolean checkChildElements( Element element, boolean isTopLevel ) {
 646  0
       int childCount = element.getChildCount();
 647  0
       Elements elements = element.getChildElements();
 648  0
       int elementCount = elements.size();
 649  
 
 650  0
       if( childCount == 1 && element.getChild( 0 ) instanceof Text ){
 651  0
          return isTopLevel;
 652  
       }
 653  
 
 654  0
       if( childCount == elementCount ){
 655  0
          if( elementCount == 0 ){
 656  0
             return true;
 657  
          }
 658  0
          if( elementCount == 1 ){
 659  0
             if( skipWhitespace || element.getChild( 0 ) instanceof Text ){
 660  0
                return true;
 661  
             }else{
 662  0
                return false;
 663  
             }
 664  
          }
 665  
       }
 666  
 
 667  0
       if( childCount > elementCount ){
 668  0
          for( int i = 0; i < childCount; i++ ){
 669  0
             Node node = element.getChild( i );
 670  0
             if( node instanceof Text ){
 671  0
                Text text = (Text) node;
 672  0
                if( StringUtils.isNotBlank( StringUtils.strip( text.getValue() ) )
 673  
                      && !skipWhitespace ){
 674  0
                   return false;
 675  
                }
 676  
             }
 677  
          }
 678  
       }
 679  
 
 680  0
       String childName = elements.get( 0 )
 681  
             .getQualifiedName();
 682  0
       for( int i = 1; i < elementCount; i++ ){
 683  0
          if( childName.compareTo( elements.get( i )
 684  
                .getQualifiedName() ) != 0 ){
 685  0
             return false;
 686  
          }
 687  
       }
 688  
 
 689  0
       return true;
 690  
    }
 691  
 
 692  
    private String getClass( Element element ) {
 693  0
       Attribute attribute = element.getAttribute( addJsonPrefix( "class" ) );
 694  0
       String clazz = null;
 695  0
       if( attribute != null ){
 696  0
          String clazzText = attribute.getValue()
 697  
                .trim();
 698  0
          if( JSONTypes.OBJECT.compareToIgnoreCase( clazzText ) == 0 ){
 699  0
             clazz = JSONTypes.OBJECT;
 700  0
          }else if( JSONTypes.ARRAY.compareToIgnoreCase( clazzText ) == 0 ){
 701  0
             clazz = JSONTypes.ARRAY;
 702  
          }
 703  
       }
 704  0
       return clazz;
 705  
    }
 706  
 
 707  
    private String getType( Element element ) {
 708  0
       return getType( element, null );
 709  
    }
 710  
 
 711  
    private String getType( Element element, String defaultType ) {
 712  0
       Attribute attribute = element.getAttribute( addJsonPrefix( "type" ) );
 713  0
       String type = null;
 714  0
       if( attribute != null ){
 715  0
          String typeText = attribute.getValue()
 716  
                .trim();
 717  0
          if( JSONTypes.BOOLEAN.compareToIgnoreCase( typeText ) == 0 ){
 718  0
             type = JSONTypes.BOOLEAN;
 719  0
          }else if( JSONTypes.NUMBER.compareToIgnoreCase( typeText ) == 0 ){
 720  0
             type = JSONTypes.NUMBER;
 721  0
          }else if( JSONTypes.INTEGER.compareToIgnoreCase( typeText ) == 0 ){
 722  0
             type = JSONTypes.INTEGER;
 723  0
          }else if( JSONTypes.FLOAT.compareToIgnoreCase( typeText ) == 0 ){
 724  0
             type = JSONTypes.FLOAT;
 725  0
          }else if( JSONTypes.OBJECT.compareToIgnoreCase( typeText ) == 0 ){
 726  0
             type = JSONTypes.OBJECT;
 727  0
          }else if( JSONTypes.ARRAY.compareToIgnoreCase( typeText ) == 0 ){
 728  0
             type = JSONTypes.ARRAY;
 729  0
          }else if( JSONTypes.STRING.compareToIgnoreCase( typeText ) == 0 ){
 730  0
             type = JSONTypes.STRING;
 731  0
          }else if( JSONTypes.FUNCTION.compareToIgnoreCase( typeText ) == 0 ){
 732  0
             type = JSONTypes.FUNCTION;
 733  
          }
 734  0
       }else{
 735  0
          if( defaultType != null ){
 736  0
             log.info( "Using default type " + defaultType );
 737  0
             type = defaultType;
 738  
          }
 739  
       }
 740  0
       return type;
 741  
    }
 742  
 
 743  
    private boolean hasNamespaces( Element element ) {
 744  0
       int namespaces = 0;
 745  0
       for( int i = 0; i < element.getNamespaceDeclarationCount(); i++ ){
 746  0
          String prefix = element.getNamespacePrefix( i );
 747  0
          String uri = element.getNamespaceURI( prefix );
 748  0
          if( StringUtils.isBlank( uri ) ){
 749  0
             continue;
 750  
          }
 751  0
          namespaces++;
 752  
       }
 753  0
       return namespaces > 0;
 754  
    }
 755  
 
 756  
    private boolean isArray( Element element, boolean isTopLevel ) {
 757  0
       boolean isArray = false;
 758  0
       String clazz = getClass( element );
 759  0
       if( clazz != null && clazz.equals( JSONTypes.ARRAY ) ){
 760  0
          isArray = true;
 761  0
       }else if( element.getAttributeCount() == 0 ){
 762  0
          isArray = checkChildElements( element, isTopLevel );
 763  0
       }else if( element.getAttributeCount() == 1
 764  
             && (element.getAttribute( addJsonPrefix( "class" ) ) != null || element.getAttribute( addJsonPrefix( "type" ) ) != null) ){
 765  0
          isArray = checkChildElements( element, isTopLevel );
 766  0
       }else if( element.getAttributeCount() == 2
 767  
             && (element.getAttribute( addJsonPrefix( "class" ) ) != null && element.getAttribute( addJsonPrefix( "type" ) ) != null) ){
 768  0
          isArray = checkChildElements( element, isTopLevel );
 769  
       }
 770  
 
 771  0
       if( isArray ){
 772  
          // check namespace
 773  0
          for( int j = 0; j < element.getNamespaceDeclarationCount(); j++ ){
 774  0
             String prefix = element.getNamespacePrefix( j );
 775  0
             String uri = element.getNamespaceURI( prefix );
 776  0
             if( !StringUtils.isBlank( uri ) ){
 777  0
                return false;
 778  
             }
 779  
          }
 780  
       }
 781  
 
 782  0
       return isArray;
 783  
    }
 784  
 
 785  
    private boolean isFunction( Element element ) {
 786  0
       int attrCount = element.getAttributeCount();
 787  0
       if( attrCount > 0 ){
 788  0
          Attribute typeAttr = element.getAttribute( addJsonPrefix( "type" ) );
 789  0
          Attribute paramsAttr = element.getAttribute( addJsonPrefix( "params" ) );
 790  0
          if( attrCount == 1 && paramsAttr != null ){
 791  0
             return true;
 792  
          }
 793  0
          if( attrCount == 2 && paramsAttr != null && typeAttr != null && (typeAttr.getValue()
 794  
                .compareToIgnoreCase( JSONTypes.STRING ) == 0 || typeAttr.getValue()
 795  
                .compareToIgnoreCase( JSONTypes.FUNCTION ) == 0) ){
 796  0
             return true;
 797  
          }
 798  
       }
 799  0
       return false;
 800  
    }
 801  
 
 802  
    private boolean isNullObject( Element element ) {
 803  0
       if( element.getChildCount() == 0 ){
 804  0
          if( element.getAttributeCount() == 0 ){
 805  0
             return true;
 806  0
          }else if( element.getAttribute( addJsonPrefix( "null" ) ) != null ){
 807  0
             return true;
 808  0
          }else if( element.getAttributeCount() == 1
 809  
                && (element.getAttribute( addJsonPrefix( "class" ) ) != null || element.getAttribute( addJsonPrefix( "type" ) ) != null) ){
 810  0
             return true;
 811  0
          }else if( element.getAttributeCount() == 2
 812  
                && (element.getAttribute( addJsonPrefix( "class" ) ) != null && element.getAttribute( addJsonPrefix( "type" ) ) != null) ){
 813  0
             return true;
 814  
          }
 815  
       }
 816  0
       if( skipWhitespace && element.getChildCount() == 1 && element.getChild( 0 ) instanceof Text ){
 817  0
          return true;
 818  
       }
 819  0
       return false;
 820  
    }
 821  
 
 822  
    private boolean isObject( Element element, boolean isTopLevel ) {
 823  0
       boolean isObject = false;
 824  0
       if( !isArray( element, isTopLevel ) && !isFunction( element ) ){
 825  0
          if( hasNamespaces( element ) ){
 826  0
             return true;
 827  
          }
 828  
 
 829  0
          int attributeCount = element.getAttributeCount();
 830  0
          if( attributeCount > 0 ){
 831  0
             int attrs = element.getAttribute( addJsonPrefix( "null" )) == null ? 0 : 1;
 832  0
             attrs += element.getAttribute( addJsonPrefix( "class" )) == null ? 0: 1;
 833  0
             attrs += element.getAttribute( addJsonPrefix( "type" ))== null ? 0 : 1;
 834  0
             switch( attributeCount ){
 835  
                case 1:
 836  0
                   if( attrs == 0){
 837  0
                      return true;
 838  
                   }
 839  
                   break;
 840  
                case 2:
 841  0
                   if( attrs < 2 ){
 842  0
                      return true;
 843  
                   }
 844  
                   break;
 845  
                case 3: 
 846  0
                   if(  attrs < 3 ){
 847  0
                      return true;
 848  
                   }
 849  
                   break;
 850  
                default:
 851  0
                   return true;
 852  
             }
 853  
          }
 854  
          
 855  0
          int childCount = element.getChildCount();
 856  0
          if( childCount == 1 && element.getChild( 0 ) instanceof Text ){
 857  0
             return isTopLevel;
 858  
          }
 859  
 
 860  0
          isObject = true;
 861  
       }
 862  0
       return isObject;
 863  
    }
 864  
 
 865  
    private Element newElement( String name ) {
 866  0
       if( name.indexOf( ':' ) != -1 ){
 867  0
          namespaceLenient = true;
 868  
       }
 869  0
       return namespaceLenient ? new CustomElement( name ) : new Element( name );
 870  
    }
 871  
 
 872  
    private JSON processArrayElement( Element element, String defaultType ) {
 873  0
       JSONArray jsonArray = new JSONArray();
 874  
       // process children (including text)
 875  0
       int childCount = element.getChildCount();
 876  0
       for( int i = 0; i < childCount; i++ ){
 877  0
          Node child = element.getChild( i );
 878  0
          if( child instanceof Text ){
 879  0
             Text text = (Text) child;
 880  0
             if( StringUtils.isNotBlank( StringUtils.strip( text.getValue() ) ) ){
 881  0
                jsonArray.element( text.getValue() );
 882  
             }
 883  0
          }else if( child instanceof Element ){
 884  0
             setValue( jsonArray, (Element) child, defaultType );
 885  
          }
 886  
       }
 887  0
       return jsonArray;
 888  
    }
 889  
 
 890  
    private Object processElement( Element element, String type ) {
 891  0
       if( isNullObject( element ) ){
 892  0
          return JSONNull.getInstance();
 893  0
       }else if( isArray( element, false ) ){
 894  0
          return processArrayElement( element, type );
 895  0
       }else if( isObject( element, false ) ){
 896  0
          return processObjectElement( element, type );
 897  
       }else{
 898  0
          return trimSpaceFromValue( element.getValue() );
 899  
       }
 900  
    }
 901  
 
 902  
    private Element processJSONArray( JSONArray array, Element root, String[] expandableProperties ) {
 903  0
       int l = array.size();
 904  0
       for( int i = 0; i < l; i++ ){
 905  0
          Object value = array.get( i );
 906  0
          Element element = processJSONValue( value, root, null, expandableProperties );
 907  0
          root.appendChild( element );
 908  
       }
 909  0
       return root;
 910  
    }
 911  
 
 912  
    private Element processJSONObject( JSONObject jsonObject, Element root,
 913  
          String[] expandableProperties, boolean isRoot ) {
 914  0
       if( jsonObject.isNullObject() ){
 915  0
          root.addAttribute( new Attribute( addJsonPrefix( "null" ), "true" ) );
 916  0
          return root;
 917  0
       }else if( jsonObject.isEmpty() ){
 918  0
          return root;
 919  
       }
 920  
 
 921  0
       if( isRoot ){
 922  0
          if( !rootNamespace.isEmpty() ){
 923  0
             setNamespaceLenient( true );
 924  0
             for( Iterator entries = rootNamespace.entrySet()
 925  0
                   .iterator(); entries.hasNext(); ){
 926  0
                Map.Entry entry = (Map.Entry) entries.next();
 927  0
                String prefix = (String) entry.getKey();
 928  0
                String uri = (String) entry.getValue();
 929  0
                if( StringUtils.isBlank( prefix ) ){
 930  0
                   root.setNamespaceURI( uri );
 931  
                }else{
 932  0
                   root.addNamespaceDeclaration( prefix, uri );
 933  
                }
 934  0
             }
 935  
          }
 936  
       }
 937  
 
 938  0
       addNameSpaceToElement( root );
 939  
 
 940  0
       Object[] names = jsonObject.names()
 941  
             .toArray();
 942  0
       Arrays.sort( names );
 943  0
       Element element = null;
 944  0
       for( int i = 0; i < names.length; i++ ){
 945  0
          String name = (String) names[i];
 946  0
          Object value = jsonObject.get( name );
 947  0
          if( name.startsWith( "@xmlns" ) ){
 948  0
             setNamespaceLenient( true );
 949  0
             int colon = name.indexOf( ':' );
 950  0
             if( colon == -1 ){
 951  
                // do not override if already defined by nameSpaceMaps
 952  0
                if( StringUtils.isBlank( root.getNamespaceURI() ) ){
 953  0
                   root.setNamespaceURI( String.valueOf( value ) );
 954  
                }
 955  
             }else{
 956  0
                String prefix = name.substring( colon + 1 );
 957  0
                if( StringUtils.isBlank( root.getNamespaceURI( prefix ) ) ){
 958  0
                   root.addNamespaceDeclaration( prefix, String.valueOf( value ) );
 959  
                }
 960  
             }
 961  0
          }else if( name.startsWith( "@" ) ){
 962  0
             root.addAttribute( new Attribute( name.substring( 1 ), String.valueOf( value ) ) );
 963  0
          }else if( name.equals( "#text" ) ){
 964  0
             if( value instanceof JSONArray ){
 965  0
                root.appendChild( ((JSONArray) value).join( "", true ) );
 966  
             }else{
 967  0
                root.appendChild( String.valueOf( value ) );
 968  
             }
 969  0
          }else if( value instanceof JSONArray
 970  
                && (((JSONArray) value).isExpandElements() || ArrayUtils.contains(
 971  
                      expandableProperties, name )) ){
 972  0
             JSONArray array = (JSONArray) value;
 973  0
             int l = array.size();
 974  0
             for( int j = 0; j < l; j++ ){
 975  0
                Object item = array.get( j );
 976  0
                element = newElement( name );
 977  0
                if( item instanceof JSONObject ){
 978  0
                   element = processJSONValue( (JSONObject) item, root, element,
 979  
                         expandableProperties );
 980  0
                }else if( item instanceof JSONArray ){
 981  0
                   element = processJSONValue( (JSONArray) item, root, element, expandableProperties );
 982  
                }else{
 983  0
                   element = processJSONValue( item, root, element, expandableProperties );
 984  
                }
 985  0
                addNameSpaceToElement( element );
 986  0
                root.appendChild( element );
 987  
             }
 988  0
          }else{
 989  0
             element = newElement( name );
 990  0
             element = processJSONValue( value, root, element, expandableProperties );
 991  0
             addNameSpaceToElement( element );
 992  0
             root.appendChild( element );
 993  
          }
 994  
       }
 995  0
       return root;
 996  
    }
 997  
 
 998  
    private Element processJSONValue( Object value, Element root, Element target,
 999  
          String[] expandableProperties ) {
 1000  0
       if( target == null ){
 1001  0
          target = newElement( getElementName() );
 1002  
       }
 1003  0
       if( JSONUtils.isBoolean( value ) ){
 1004  0
          if( isTypeHintsEnabled() ){
 1005  0
             target.addAttribute( new Attribute( addJsonPrefix( "type" ), JSONTypes.BOOLEAN ) );
 1006  
          }
 1007  0
          target.appendChild( value.toString() );
 1008  0
       }else if( JSONUtils.isNumber( value ) ){
 1009  0
          if( isTypeHintsEnabled() ){
 1010  0
             target.addAttribute( new Attribute( addJsonPrefix( "type" ), JSONTypes.NUMBER ) );
 1011  
          }
 1012  0
          target.appendChild( value.toString() );
 1013  0
       }else if( JSONUtils.isFunction( value ) ){
 1014  0
          if( value instanceof String ){
 1015  0
             value = JSONFunction.parse( (String) value );
 1016  
          }
 1017  0
          JSONFunction func = (JSONFunction) value;
 1018  0
          if( isTypeHintsEnabled() ){
 1019  0
             target.addAttribute( new Attribute( addJsonPrefix( "type" ), JSONTypes.FUNCTION ) );
 1020  
          }
 1021  0
          String params = ArrayUtils.toString( func.getParams() );
 1022  0
          params = params.substring( 1 );
 1023  0
          params = params.substring( 0, params.length() - 1 );
 1024  0
          target.addAttribute( new Attribute( addJsonPrefix( "params" ), params ) );
 1025  0
          target.appendChild( new Text( "<![CDATA[" + func.getText() + "]]>" ) );
 1026  0
       }else if( JSONUtils.isString( value ) ){
 1027  0
          if( isTypeHintsEnabled() ){
 1028  0
             target.addAttribute( new Attribute( addJsonPrefix( "type" ), JSONTypes.STRING ) );
 1029  
          }
 1030  0
          target.appendChild( value.toString() );
 1031  0
       }else if( value instanceof JSONArray ){
 1032  0
          if( isTypeHintsEnabled() ){
 1033  0
             target.addAttribute( new Attribute( addJsonPrefix( "class" ), JSONTypes.ARRAY ) );
 1034  
          }
 1035  0
          target = processJSONArray( (JSONArray) value, target, expandableProperties );
 1036  0
       }else if( value instanceof JSONObject ){
 1037  0
          if( isTypeHintsEnabled() ){
 1038  0
             target.addAttribute( new Attribute( addJsonPrefix( "class" ), JSONTypes.OBJECT ) );
 1039  
          }
 1040  0
          target = processJSONObject( (JSONObject) value, target, expandableProperties, false );
 1041  0
       }else if( JSONUtils.isNull( value ) ){
 1042  0
          if( isTypeHintsEnabled() ){
 1043  0
             target.addAttribute( new Attribute( addJsonPrefix( "class" ), JSONTypes.OBJECT ) );
 1044  
          }
 1045  0
          target.addAttribute( new Attribute( addJsonPrefix( "null" ), "true" ) );
 1046  
       }
 1047  0
       return target;
 1048  
    }
 1049  
 
 1050  
    private JSON processObjectElement( Element element, String defaultType ) {
 1051  0
       if( isNullObject( element ) ){
 1052  0
          return JSONNull.getInstance();
 1053  
       }
 1054  0
       JSONObject jsonObject = new JSONObject();
 1055  
 
 1056  0
       if( !skipNamespaces ){
 1057  0
          for( int j = 0; j < element.getNamespaceDeclarationCount(); j++ ){
 1058  0
             String prefix = element.getNamespacePrefix( j );
 1059  0
             String uri = element.getNamespaceURI( prefix );
 1060  0
             if( StringUtils.isBlank( uri ) ){
 1061  0
                continue;
 1062  
             }
 1063  0
             if( !StringUtils.isBlank( prefix ) ){
 1064  0
                prefix = ":" + prefix;
 1065  
             }
 1066  0
             setOrAccumulate( jsonObject, "@xmlns" + prefix, trimSpaceFromValue( uri ) );
 1067  
          }
 1068  
       }
 1069  
      
 1070  
       // process attributes first
 1071  0
       int attrCount = element.getAttributeCount();
 1072  0
       for( int i = 0; i < attrCount; i++ ){
 1073  0
          Attribute attr = element.getAttribute( i );
 1074  0
          String attrname = attr.getQualifiedName();
 1075  0
          if( isTypeHintsEnabled()
 1076  
                && (addJsonPrefix( "class" ).compareToIgnoreCase( attrname ) == 0 || addJsonPrefix(
 1077  
                      "type" ).compareToIgnoreCase( attrname ) == 0) ){
 1078  0
             continue;
 1079  
          }
 1080  0
          String attrvalue = attr.getValue();
 1081  0
          setOrAccumulate( jsonObject, "@" + removeNamespacePrefix( attrname ),
 1082  
                trimSpaceFromValue( attrvalue ) );
 1083  
       }
 1084  
 
 1085  
       // process children (including text)
 1086  0
       int childCount = element.getChildCount();
 1087  0
       for( int i = 0; i < childCount; i++ ){
 1088  0
          Node child = element.getChild( i );
 1089  0
          if( child instanceof Text ){
 1090  0
             Text text = (Text) child;
 1091  0
             if( StringUtils.isNotBlank( StringUtils.strip( text.getValue() ) ) ){
 1092  0
                setOrAccumulate( jsonObject, "#text", trimSpaceFromValue( text.getValue() ) );
 1093  
             }
 1094  0
          }else if( child instanceof Element ){
 1095  0
             setValue( jsonObject, (Element) child, defaultType );
 1096  
          }
 1097  
       }
 1098  
 
 1099  0
       return jsonObject;
 1100  
    }
 1101  
 
 1102  
    private String removeNamespacePrefix( String name ) {
 1103  0
       if( isRemoveNamespacePrefixFromElements() ){
 1104  0
          int colon = name.indexOf( ':' );
 1105  0
          return colon != -1 ? name.substring( colon + 1 ) : name;
 1106  
       }
 1107  0
       return name;
 1108  
    }
 1109  
 
 1110  
    private void setOrAccumulate( JSONObject jsonObject, String key, Object value ) {
 1111  0
       if( jsonObject.has( key ) ){
 1112  0
          jsonObject.accumulate( key, value );
 1113  0
          Object val = jsonObject.get( key );
 1114  0
          if( val instanceof JSONArray ){
 1115  0
             ((JSONArray) val).setExpandElements( true );
 1116  
          }
 1117  0
       }else{
 1118  0
          jsonObject.element( key, value );
 1119  
       }
 1120  0
    }
 1121  
 
 1122  
    private void setValue( JSONArray jsonArray, Element element, String defaultType ) {
 1123  0
       String clazz = getClass( element );
 1124  0
       String type = getType( element );
 1125  0
       type = (type == null) ? defaultType : type;
 1126  
 
 1127  0
       if( hasNamespaces( element ) && !skipNamespaces ){
 1128  0
          jsonArray.element( simplifyValue( null, processElement( element, type ) ) );
 1129  0
          return;
 1130  0
       }else if( element.getAttributeCount() > 0 ){
 1131  0
          if( isFunction( element ) ){
 1132  0
             Attribute paramsAttribute = element.getAttribute( addJsonPrefix( "params" ) );
 1133  0
             String[] params = null;
 1134  0
             String text = element.getValue();
 1135  0
             params = StringUtils.split( paramsAttribute.getValue(), "," );
 1136  0
             jsonArray.element( new JSONFunction( params, text ) );
 1137  0
             return;
 1138  
          }else{
 1139  0
             jsonArray.element( simplifyValue( null, processElement( element, type ) ) );
 1140  0
             return;
 1141  
          }
 1142  
       }
 1143  
 
 1144  0
       boolean classProcessed = false;
 1145  0
       if( clazz != null ){
 1146  0
          if( clazz.compareToIgnoreCase( JSONTypes.ARRAY ) == 0 ){
 1147  0
             jsonArray.element( processArrayElement( element, type ) );
 1148  0
             classProcessed = true;
 1149  0
          }else if( clazz.compareToIgnoreCase( JSONTypes.OBJECT ) == 0 ){
 1150  0
             jsonArray.element( simplifyValue( null, processObjectElement( element, type ) ) );
 1151  0
             classProcessed = true;
 1152  
          }
 1153  
       }
 1154  0
       if( !classProcessed ){
 1155  0
          if( type.compareToIgnoreCase( JSONTypes.BOOLEAN ) == 0 ){
 1156  0
             jsonArray.element( Boolean.valueOf( element.getValue() ) );
 1157  0
          }else if( type.compareToIgnoreCase( JSONTypes.NUMBER ) == 0 ){
 1158  
             // try integer first
 1159  
             try{
 1160  0
                jsonArray.element( Integer.valueOf( element.getValue() ) );
 1161  0
             }catch( NumberFormatException e ){
 1162  0
                jsonArray.element( Double.valueOf( element.getValue() ) );
 1163  0
             }
 1164  0
          }else if( type.compareToIgnoreCase( JSONTypes.INTEGER ) == 0 ){
 1165  0
             jsonArray.element( Integer.valueOf( element.getValue() ) );
 1166  0
          }else if( type.compareToIgnoreCase( JSONTypes.FLOAT ) == 0 ){
 1167  0
             jsonArray.element( Double.valueOf( element.getValue() ) );
 1168  0
          }else if( type.compareToIgnoreCase( JSONTypes.FUNCTION ) == 0 ){
 1169  0
             String[] params = null;
 1170  0
             String text = element.getValue();
 1171  0
             Attribute paramsAttribute = element.getAttribute( addJsonPrefix( "params" ) );
 1172  0
             if( paramsAttribute != null ){
 1173  0
                params = StringUtils.split( paramsAttribute.getValue(), "," );
 1174  
             }
 1175  0
             jsonArray.element( new JSONFunction( params, text ) );
 1176  0
          }else if( type.compareToIgnoreCase( JSONTypes.STRING ) == 0 ){
 1177  
             // see if by any chance has a 'params' attribute
 1178  0
             Attribute paramsAttribute = element.getAttribute( addJsonPrefix( "params" ) );
 1179  0
             if( paramsAttribute != null ){
 1180  0
                String[] params = null;
 1181  0
                String text = element.getValue();
 1182  0
                params = StringUtils.split( paramsAttribute.getValue(), "," );
 1183  0
                jsonArray.element( new JSONFunction( params, text ) );
 1184  0
             }else{
 1185  0
                if( isArray( element, false ) ){
 1186  0
                   jsonArray.element( processArrayElement( element, defaultType ) );
 1187  0
                }else if( isObject( element, false ) ){
 1188  0
                   jsonArray.element( simplifyValue( null, processObjectElement( element,
 1189  
                         defaultType ) ) );
 1190  
                }else{
 1191  0
                   jsonArray.element( trimSpaceFromValue( element.getValue() ) );
 1192  
                }
 1193  
             }
 1194  
          }
 1195  
       }
 1196  0
    }
 1197  
 
 1198  
    private void setValue( JSONObject jsonObject, Element element, String defaultType ) {
 1199  0
       String clazz = getClass( element );
 1200  0
       String type = getType( element );
 1201  0
       type = (type == null) ? defaultType : type;
 1202  
   
 1203  
       
 1204  
       
 1205  0
       String key = removeNamespacePrefix( element.getQualifiedName() );
 1206  0
       if( hasNamespaces( element ) && !skipNamespaces ){
 1207  0
          setOrAccumulate( jsonObject, key, simplifyValue( jsonObject,
 1208  
                processElement( element, type ) ) );
 1209  0
          return;
 1210  0
       }else if( element.getAttributeCount() > 0 ){
 1211  0
          if( isFunction( element ) ){
 1212  0
             Attribute paramsAttribute = element.getAttribute( addJsonPrefix( "params" ) );
 1213  0
             String text = element.getValue();
 1214  0
             String[] params = StringUtils.split( paramsAttribute.getValue(), "," );
 1215  0
             setOrAccumulate( jsonObject, key, new JSONFunction( params, text ) );
 1216  0
             return;
 1217  
          }/*else{
 1218  
             setOrAccumulate( jsonObject, key, simplifyValue( jsonObject, processElement( element,
 1219  
                   type ) ) );
 1220  
             return;
 1221  
          }*/
 1222  
       }
 1223  
 
 1224  0
       boolean classProcessed = false;
 1225  0
       if( clazz != null ){
 1226  0
          if( clazz.compareToIgnoreCase( JSONTypes.ARRAY ) == 0 ){
 1227  0
             setOrAccumulate( jsonObject, key, processArrayElement( element, type ) );
 1228  0
             classProcessed = true;
 1229  0
          }else if( clazz.compareToIgnoreCase( JSONTypes.OBJECT ) == 0 ){
 1230  0
             setOrAccumulate( jsonObject, key, simplifyValue( jsonObject, processObjectElement(
 1231  
                   element, type ) ) );
 1232  0
             classProcessed = true;
 1233  
          }
 1234  
       }
 1235  0
       if( !classProcessed ){
 1236  0
          if( type.compareToIgnoreCase( JSONTypes.BOOLEAN ) == 0 ){
 1237  0
             setOrAccumulate( jsonObject, key, Boolean.valueOf( element.getValue() ) );
 1238  0
          }else if( type.compareToIgnoreCase( JSONTypes.NUMBER ) == 0 ){
 1239  
             // try integer first
 1240  
             try{
 1241  0
                setOrAccumulate( jsonObject, key, Integer.valueOf( element.getValue() ) );
 1242  0
             }catch( NumberFormatException e ){
 1243  0
                setOrAccumulate( jsonObject, key, Double.valueOf( element.getValue() ) );
 1244  0
             }
 1245  0
          }else if( type.compareToIgnoreCase( JSONTypes.INTEGER ) == 0 ){
 1246  0
             setOrAccumulate( jsonObject, key, Integer.valueOf( element.getValue() ) );
 1247  0
          }else if( type.compareToIgnoreCase( JSONTypes.FLOAT ) == 0 ){
 1248  0
             setOrAccumulate( jsonObject, key, Double.valueOf( element.getValue() ) );
 1249  0
          }else if( type.compareToIgnoreCase( JSONTypes.FUNCTION ) == 0 ){
 1250  0
             String[] params = null;
 1251  0
             String text = element.getValue();
 1252  0
             Attribute paramsAttribute = element.getAttribute( addJsonPrefix( "params" ) );
 1253  0
             if( paramsAttribute != null ){
 1254  0
                params = StringUtils.split( paramsAttribute.getValue(), "," );
 1255  
             }
 1256  0
             setOrAccumulate( jsonObject, key, new JSONFunction( params, text ) );
 1257  0
          }else if( type.compareToIgnoreCase( JSONTypes.STRING ) == 0 ){
 1258  
             // see if by any chance has a 'params' attribute
 1259  0
             Attribute paramsAttribute = element.getAttribute( addJsonPrefix( "params" ) );
 1260  0
             if( paramsAttribute != null ){
 1261  0
                String[] params = null;
 1262  0
                String text = element.getValue();
 1263  0
                params = StringUtils.split( paramsAttribute.getValue(), "," );
 1264  0
                setOrAccumulate( jsonObject, key, new JSONFunction( params, text ) );
 1265  0
             }else{
 1266  0
                if( isArray( element, false ) ){
 1267  0
                   setOrAccumulate( jsonObject, key, processArrayElement( element, defaultType ) );
 1268  0
                }else if( isObject( element, false ) ){
 1269  0
                   setOrAccumulate( jsonObject, key, simplifyValue( jsonObject,
 1270  
                         processObjectElement( element, defaultType ) ) );
 1271  
                }else{
 1272  0
                   setOrAccumulate( jsonObject, key, trimSpaceFromValue( element.getValue() ) );
 1273  
                }
 1274  
             }
 1275  
          }
 1276  
       }
 1277  0
    }
 1278  
 
 1279  
    private Object simplifyValue( JSONObject parent, Object json ) {
 1280  0
       if( json instanceof JSONObject ){
 1281  0
          JSONObject object = (JSONObject) json;
 1282  0
          if( parent != null ){
 1283  
             // remove all duplicated @xmlns from child
 1284  0
             for( Iterator entries = parent.entrySet()
 1285  0
                   .iterator(); entries.hasNext(); ){
 1286  0
                Map.Entry entry = (Map.Entry) entries.next();
 1287  0
                String key = (String) entry.getKey();
 1288  0
                Object value = entry.getValue();
 1289  0
                if( key.startsWith( "@xmlns" ) && value.equals( object.opt( key ) ) ){
 1290  0
                   object.remove( key );
 1291  
                }
 1292  0
             }
 1293  
          }
 1294  0
          if( object.size() == 1 && object.has( "#text" ) ){
 1295  0
             return object.get( "#text" );
 1296  
          }
 1297  
       }
 1298  0
       return json;
 1299  
    }
 1300  
    private String trimSpaceFromValue( String value ) {
 1301  0
       if( isTrimSpaces() ){
 1302  0
          return value.trim();
 1303  
       }
 1304  0
       return value;
 1305  
    }
 1306  
    private String writeDocument( Document doc, String encoding ) {
 1307  0
       ByteArrayOutputStream baos = new ByteArrayOutputStream();
 1308  
       try{
 1309  0
          XomSerializer serializer = (encoding == null) ? new XomSerializer( baos )
 1310  
                : new XomSerializer( baos, encoding );
 1311  0
          serializer.write( doc );
 1312  0
          encoding = serializer.getEncoding();
 1313  0
       }catch( IOException ioe ){
 1314  0
          throw new JSONException( ioe );
 1315  0
       }
 1316  
 
 1317  0
       String str = null;
 1318  
       try{
 1319  0
          str = baos.toString( encoding );
 1320  0
       }catch( UnsupportedEncodingException uee ){
 1321  0
          throw new JSONException( uee );
 1322  0
       }
 1323  0
       return str;
 1324  
    }
 1325  
 
 1326  
    private static class CustomElement extends Element {
 1327  
       private static String getName( String name ) {
 1328  0
          int colon = name.indexOf( ':' );
 1329  0
          if( colon != -1 ){
 1330  0
             return name.substring( colon + 1 );
 1331  
          }
 1332  0
          return name;
 1333  
       }
 1334  
 
 1335  
       private static String getPrefix( String name ) {
 1336  0
          int colon = name.indexOf( ':' );
 1337  0
          if( colon != -1 ){
 1338  0
             return name.substring( 0, colon );
 1339  
          }
 1340  0
          return "";
 1341  
       }
 1342  
 
 1343  
       private String prefix;
 1344  
 
 1345  
       public CustomElement( String name ) {
 1346  0
          super( CustomElement.getName( name ) );
 1347  0
          prefix = CustomElement.getPrefix( name );
 1348  0
       }
 1349  
 
 1350  
       public final String getQName() {
 1351  0
          if( prefix.length() == 0 ){
 1352  0
             return getLocalName();
 1353  
          }else{
 1354  0
             return prefix + ":" + getLocalName();
 1355  
          }
 1356  
       }
 1357  
    }
 1358  
 
 1359  
    private class XomSerializer extends Serializer {
 1360  0
       public XomSerializer( OutputStream out ) {
 1361  0
          super( out );
 1362  0
       }
 1363  
 
 1364  0
       public XomSerializer( OutputStream out, String encoding ) throws UnsupportedEncodingException {
 1365  0
          super( out, encoding );
 1366  0
       }
 1367  
 
 1368  
       protected void write( Text text ) throws IOException {
 1369  0
          String value = text.getValue();
 1370  0
          if( value.startsWith( "<![CDATA[" ) && value.endsWith( "]]>" ) ){
 1371  0
             value = value.substring( 9 );
 1372  0
             value = value.substring( 0, value.length() - 3 );
 1373  0
             writeRaw( "<![CDATA[" );
 1374  0
             writeRaw( value );
 1375  0
             writeRaw( "]]>" );
 1376  
          }else{
 1377  0
             super.write( text );
 1378  
          }
 1379  0
       }
 1380  
 
 1381  
       protected void writeEmptyElementTag( Element element ) throws IOException {
 1382  0
          if( element instanceof CustomElement && isNamespaceLenient() ){
 1383  0
             writeTagBeginning( (CustomElement) element );
 1384  0
             writeRaw( "/>" );
 1385  
          }else{
 1386  0
             super.writeEmptyElementTag( element );
 1387  
          }
 1388  0
       }
 1389  
 
 1390  
       protected void writeEndTag( Element element ) throws IOException {
 1391  0
          if( element instanceof CustomElement && isNamespaceLenient() ){
 1392  0
             writeRaw( "</" );
 1393  0
             writeRaw( ((CustomElement) element).getQName() );
 1394  0
             writeRaw( ">" );
 1395  
          }else{
 1396  0
             super.writeEndTag( element );
 1397  
          }
 1398  0
       }
 1399  
 
 1400  
       protected void writeNamespaceDeclaration( String prefix, String uri ) throws IOException {
 1401  0
          if( !StringUtils.isBlank( uri ) ){
 1402  0
             super.writeNamespaceDeclaration( prefix, uri );
 1403  
          }
 1404  0
       }
 1405  
 
 1406  
       protected void writeStartTag( Element element ) throws IOException {
 1407  0
          if( element instanceof CustomElement && isNamespaceLenient() ){
 1408  0
             writeTagBeginning( (CustomElement) element );
 1409  0
             writeRaw( ">" );
 1410  
          }else{
 1411  0
             super.writeStartTag( element );
 1412  
          }
 1413  0
       }
 1414  
 
 1415  
       private void writeTagBeginning( CustomElement element ) throws IOException {
 1416  0
          writeRaw( "<" );
 1417  0
          writeRaw( element.getQName() );
 1418  0
          writeAttributes( element );
 1419  0
          writeNamespaceDeclarations( element );
 1420  0
       }
 1421  
    }
 1422  
 }