themeinstaller/source/src/com/nokia/tools/themeinstaller/odtconverter/DOMExternalizer.java
branchRCL_3
changeset 32 fe49e33862e2
parent 31 b685c59de105
child 33 04b7640f6fb5
equal deleted inserted replaced
31:b685c59de105 32:fe49e33862e2
     1 /*
       
     2 * Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies). 
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  Externalizes a DOM Document to a byte array.
       
    15  *
       
    16 */
       
    17 
       
    18 
       
    19 package com.nokia.tools.themeinstaller.odtconverter;
       
    20 
       
    21 import java.awt.Color;
       
    22 import java.io.ByteArrayOutputStream;
       
    23 import java.io.IOException;
       
    24 
       
    25 import org.w3c.dom.Document;
       
    26 import org.w3c.dom.Element;
       
    27 import org.w3c.dom.NamedNodeMap;
       
    28 import org.w3c.dom.Node;
       
    29 import org.w3c.dom.NodeList;
       
    30 
       
    31 import com.nokia.tools.themeinstaller.cssparser.CSSDOMProcessor;
       
    32 import com.nokia.tools.themeinstaller.cssparser.CSSHandler;
       
    33 import com.nokia.tools.themeinstaller.cssparser.PseudoClassResolver;
       
    34 
       
    35 /**
       
    36  * Externalizes DOM Document to a byte array.
       
    37  */
       
    38 public class DOMExternalizer
       
    39     {
       
    40 
       
    41     // CONSTANTS
       
    42     // Text elements according to CXnDomVisitor::KXnElementVisitorTable and
       
    43     // CXnODTParser
       
    44     private static final String TEXT_ELEMENT = "text";
       
    45     private static final String DESC_ELEMENT = "desc";
       
    46     private static final String MARQUEE_ELEMENT = "marquee";
       
    47     private static final String OBJECT_ELEMENT = "object";
       
    48     private static final String NEWSTICKER_ELEMENT = "newsticker";
       
    49 
       
    50     // Attribute name if node is refnode
       
    51     private static final String REF_NODE = "ref";
       
    52 
       
    53     // List types
       
    54     private static final int UNKNOWN = -1;
       
    55     private static final int NODE = 0;
       
    56     private static final int ATTRIBUTE = 1;
       
    57     private static final int PROPERTY = 2;
       
    58 
       
    59     // The Constant COLOR_TABLE_SIZE
       
    60     private static final int COLOR_TABLE_SIZE = 3;
       
    61 
       
    62     // Pseudo class resolver
       
    63     private PseudoClassResolver iPseudoResolver;
       
    64 
       
    65     // The value type resolver
       
    66     private ValueTypeResolver iValueTypeResolver;
       
    67 
       
    68     // String pool
       
    69     private StringPool iStringPool;
       
    70 
       
    71     // DOM Document
       
    72     private Document iDocument;
       
    73 
       
    74     // Byte output stream for delivering the externalized data
       
    75     private ByteArrayOutputStream iBaos;
       
    76 
       
    77     // Data output stream for writing to the baos
       
    78     private ODTDataOutputStream iODTDos;
       
    79 
       
    80     // Node id and counter
       
    81     private int iCurrentNodeId = 0;
       
    82 
       
    83     /** CSSDOMProsessor for checking property's inheritance value. */
       
    84     private CSSDOMProcessor iCSSDOMProsessor;
       
    85 
       
    86     /**
       
    87      * Constructor.
       
    88      * @param aDocument DOM Document to externalize
       
    89      */
       
    90     public DOMExternalizer( Document aDocument )
       
    91         {
       
    92         iPseudoResolver = new PseudoClassResolver();
       
    93         iValueTypeResolver = new ValueTypeResolver();
       
    94         iCSSDOMProsessor = new CSSDOMProcessor();
       
    95         iStringPool = new StringPool();
       
    96         iDocument = aDocument;
       
    97         iBaos = new ByteArrayOutputStream();
       
    98         iODTDos = new ODTDataOutputStream( iBaos );
       
    99         }
       
   100 
       
   101     /* (non-Javadoc)
       
   102      * @see java.lang.Object#finalize()
       
   103      */
       
   104     protected void finalize() throws Throwable
       
   105         {
       
   106         iODTDos.close();
       
   107         iBaos.close();
       
   108         }
       
   109 
       
   110     /**
       
   111      * Externalizes the DOM document and string pool to a byte array.
       
   112      * @return Byte array containing the document
       
   113      * @throws IOException if writing to a stream fails
       
   114      * @throws ODTException
       
   115      */
       
   116     public byte[] getByteArray() throws IOException, ODTException
       
   117         {
       
   118         ByteArrayOutputStream result = new ByteArrayOutputStream();
       
   119         byte[] resultArray = null;
       
   120 
       
   121         try
       
   122             {
       
   123             // Externalize the DOM
       
   124             doExternalize();
       
   125 
       
   126             // Externalize the string pool
       
   127             result.write( iStringPool.toByteArray() );
       
   128 
       
   129             // Write the dom contents to the result baos
       
   130             result.write( iBaos.toByteArray() );
       
   131 
       
   132             resultArray = result.toByteArray();
       
   133             }
       
   134         finally
       
   135             {
       
   136             if( result != null )
       
   137                 {
       
   138                 result.close();
       
   139                 }
       
   140             }
       
   141 
       
   142         return resultArray;
       
   143         }
       
   144 
       
   145     /**
       
   146      * Do the externalization process.
       
   147      * @throws IOException if data output stream can not be written
       
   148      * @throws ODTException if there is an error with property value externalization
       
   149      */
       
   150     private void doExternalize() throws IOException, ODTException
       
   151         {
       
   152         Node rootElement = iDocument.getDocumentElement();
       
   153 
       
   154         if( rootElement != null )
       
   155             {
       
   156             // Root node exists
       
   157             iODTDos.writeBoolean( true );
       
   158             externalizeNode( ( Node )rootElement, true );
       
   159             }
       
   160         else
       
   161             {
       
   162             // No root node
       
   163             iODTDos.writeBoolean( false );
       
   164             }
       
   165         }
       
   166 
       
   167     /**
       
   168      * Externalizes a node in the DOM tree.
       
   169      * @param aNode Node to externalize
       
   170      * @param aRootNode true, if this is the root node of the tree
       
   171      * @throws IOException if data output stream can not be written
       
   172      * @throws ODTException if there is an error with property value externalization
       
   173      */
       
   174     private void externalizeNode( Node aNode, boolean aRootNode )
       
   175         throws IOException, ODTException
       
   176         {
       
   177         // Write name
       
   178         String name = aNode.getNodeName();
       
   179         int nameRef = iStringPool.addString( name );
       
   180         iODTDos.writeInt16( nameRef );
       
   181 
       
   182         // Write name space
       
   183         String ns = aNode.getNamespaceURI();
       
   184         int nsRef = iStringPool.addString( ns );
       
   185         iODTDos.writeInt16( nsRef );
       
   186 
       
   187         // Check and write refnode boolean
       
   188         iODTDos.writeBoolean( checkRefNode( aNode ) );
       
   189 
       
   190         boolean textNodeFound = false;
       
   191 
       
   192         // Write parsed character data
       
   193         StringBuffer pcData = new StringBuffer();
       
   194         if( TEXT_ELEMENT.equals( name ) ||
       
   195             DESC_ELEMENT.equals( name ) ||
       
   196             MARQUEE_ELEMENT.equals( name ) ||
       
   197             OBJECT_ELEMENT.equals( name ) ||
       
   198             NEWSTICKER_ELEMENT.equals( name ) )
       
   199             {
       
   200             NodeList list = aNode.getChildNodes();
       
   201 
       
   202             for( int i = 0; i < list.getLength() ; i++ )
       
   203                 {
       
   204                 Node nod = list.item( i );
       
   205                 if( nod.getNodeType() == Node.TEXT_NODE )
       
   206                     {
       
   207                     textNodeFound = true;
       
   208                     String textNodeValue = nod.getNodeValue();
       
   209 
       
   210                     pcData.append( textNodeValue );
       
   211                     }
       
   212                 }
       
   213             }
       
   214 
       
   215         // Write data length and the data
       
   216         iODTDos.writeBoolean( textNodeFound );
       
   217         if( textNodeFound )
       
   218             {
       
   219             // Write text length
       
   220             iODTDos.writeInt16( pcData.length() );
       
   221 
       
   222             // Write text node value
       
   223             iODTDos.writeString8( pcData.toString() );
       
   224             }
       
   225         // Update the counter and write node id
       
   226         iODTDos.writeInt32( iCurrentNodeId++ );
       
   227 
       
   228         // Externalize the child list
       
   229         externalizeNodeList( aNode );
       
   230 
       
   231         // Externalize the attribute list
       
   232         externalizeAttributeList( aNode );
       
   233 
       
   234         // Externalize the property list
       
   235         externalizePropertyList( aNode );
       
   236         }
       
   237 
       
   238     /**
       
   239      * Checks if node is refnode.
       
   240      * Node is refnode if some of node's attributes name is "ref".
       
   241      * @param aNode Node containing the attributes
       
   242      * @return boolean true if node is refnode, otherwise false
       
   243      */
       
   244     private boolean checkRefNode( Node aNode )
       
   245         {
       
   246         boolean refNode = false;
       
   247         NamedNodeMap list = aNode.getAttributes();
       
   248         for ( int i = 0; i < list.getLength(); i++ )
       
   249             {
       
   250             Node node = list.item( i );
       
   251             if ( nodeType( node ) == ATTRIBUTE )
       
   252                 {
       
   253                 if( node.getNodeName().equals( REF_NODE ) )
       
   254                     {
       
   255                     refNode = true;
       
   256                     }
       
   257                 }
       
   258             }
       
   259         return refNode;
       
   260         }
       
   261 
       
   262     /**
       
   263      * Externalizes attributes of a node.
       
   264      * @param aNode Node containing the attributes
       
   265      * @throws IOException if writing to a stream fails
       
   266      * @throws ODTException
       
   267      */
       
   268     private void externalizeAttributeNode( Node aNode )
       
   269         throws IOException, ODTException
       
   270         {
       
   271         // Write name
       
   272         String name = aNode.getNodeName();
       
   273         int nameRef = iStringPool.addString( name );
       
   274         iODTDos.writeInt16( nameRef );
       
   275 
       
   276         // Write value
       
   277         String value = aNode.getNodeValue();
       
   278         int valueRef = iStringPool.addString( value );
       
   279         iODTDos.writeInt16( valueRef );
       
   280         }
       
   281 
       
   282     /**
       
   283      * Externalizes a property node.
       
   284      *
       
   285      * @param aNode Node containing the properties
       
   286      * @param aParentNode Node's parent node
       
   287      *
       
   288      * @throws IOException if data output stream can not be written
       
   289      * @throws ODTException if there is an error with property
       
   290      * value externalization
       
   291      */
       
   292     private void externalizePropertyNode( Node aParentNode, Node aNode )
       
   293         throws IOException, ODTException
       
   294         {
       
   295         // Get property node attributes: property name, values and pseudo class
       
   296         NamedNodeMap list = aNode.getAttributes();
       
   297 
       
   298         // Property value list
       
   299         boolean isInherited = externalizePropertyValueList( aParentNode, list );
       
   300 
       
   301         iODTDos.writeBoolean( isInherited );
       
   302 
       
   303         // Resolve pseudo class
       
   304         int pseudoClass = PseudoClassResolver.NONE;
       
   305 
       
   306         int count = list.getLength();
       
   307         for( int i = 0; i < count; i++ )
       
   308             {
       
   309             // Browse through all attributes of the style property element and
       
   310             // seek for a pseudo class
       
   311             Node item = list.item( i );
       
   312             if( item.getNodeName().equals( CSSDOMProcessor.STRING_PSEUDOCLASS ) )
       
   313                 {
       
   314                 pseudoClass = iPseudoResolver.getKey( item.getNodeValue() );
       
   315                 if( pseudoClass == UNKNOWN )
       
   316                     {
       
   317                     throw new ODTException( "Error externalizing ODT/styles: " +
       
   318                     		"unknown pseudo class" );
       
   319                     }
       
   320                 break;
       
   321                 }
       
   322             }
       
   323 
       
   324         // Pseudo class -> int8
       
   325         iODTDos.writeByte( pseudoClass );
       
   326         }
       
   327 
       
   328     /**
       
   329      * Externalize a list of nodes.
       
   330      * @param aParentNode Parent node
       
   331      * @throws IOException if data output stream can not be written
       
   332      * @throws ODTException if there is an error with property value externalization
       
   333      */
       
   334     private void externalizeNodeList( Node aParentNode ) throws IOException, ODTException
       
   335         {
       
   336         // Write list type
       
   337         iODTDos.writeByte( NODE );
       
   338 
       
   339         NodeList list = aParentNode.getChildNodes();
       
   340 
       
   341         // Count element nodes
       
   342         int count = countNodes( list );
       
   343 
       
   344         // Write element node count
       
   345         iODTDos.writeInt32( count );
       
   346 
       
   347         for ( int i = 0; i < list.getLength(); i++ )
       
   348             {
       
   349             Node node = list.item( i );
       
   350 
       
   351             if ( nodeType( node ) == NODE )
       
   352                 {
       
   353                 externalizeNode( node, false );
       
   354                 }
       
   355             }
       
   356         }
       
   357 
       
   358     /**
       
   359      * Externalize a list of attributes.
       
   360      * @param aParentNode Node containing the attributes.
       
   361      * @throws IOException if writing to a stream fails
       
   362      * @throws ODTException
       
   363      */
       
   364     private void externalizeAttributeList( Node aParentNode )
       
   365             throws IOException, ODTException
       
   366         {
       
   367         // Write list type
       
   368         iODTDos.writeByte( ATTRIBUTE );
       
   369 
       
   370         NamedNodeMap list = aParentNode.getAttributes();
       
   371 
       
   372         // Count element nodes
       
   373         int count = countAttributes( list );
       
   374 
       
   375         // Write element node count
       
   376         iODTDos.writeInt32( count );
       
   377 
       
   378         for ( int i = 0; i < list.getLength(); i++ )
       
   379             {
       
   380             Node node = list.item( i );
       
   381 
       
   382             if ( nodeType( node ) == ATTRIBUTE )
       
   383                 {
       
   384                 externalizeAttributeNode( node );
       
   385                 }
       
   386             }
       
   387         }
       
   388 
       
   389     /**
       
   390      * Externalize a list of properties.
       
   391      * @param aParentNode Node containing the properties
       
   392      * @throws IOException if data output stream can not be written
       
   393      * @throws ODTException if there is an error with property value externalization
       
   394      */
       
   395     private void externalizePropertyList( Node aParentNode ) throws IOException, ODTException
       
   396         {
       
   397         // Write list type
       
   398         iODTDos.writeByte( PROPERTY );
       
   399 
       
   400         NodeList list = aParentNode.getChildNodes();
       
   401 
       
   402         // Count element nodes
       
   403         int count = countProperties( list );
       
   404 
       
   405         // Write element node count
       
   406         iODTDos.writeInt32( count );
       
   407 
       
   408         for ( int i = 0; i < list.getLength(); i++ )
       
   409             {
       
   410             Node node = list.item( i );
       
   411 
       
   412             if ( nodeType( node ) == PROPERTY )
       
   413                 {
       
   414                 externalizePropertyNode( aParentNode, node );
       
   415                 }
       
   416             }
       
   417         }
       
   418 
       
   419     /**
       
   420      * Parses a Color from string.
       
   421      *
       
   422      * @param aColor Color values in String made by CSSHandler
       
   423      *
       
   424      * @return The color
       
   425      *
       
   426      * @throws ODTException the ODT exception
       
   427      */
       
   428     private Color parseColorFromString( String aColor ) throws ODTException
       
   429         {
       
   430         String sx[] = aColor.split( CSSHandler.COMMA );
       
   431         int ix[] = new int[ sx.length ];
       
   432 
       
   433         // LexicalUnit.SAC_RGBCOLOR knows color values with format
       
   434         // rgb(0, 0, 0) and #000. That is, with three parameters
       
   435         if ( sx.length != COLOR_TABLE_SIZE )
       
   436             {
       
   437             throw new ODTException( "Error in DOM/style data externalization: "
       
   438                     + "RGB Values: parameter amount" );
       
   439             }
       
   440 
       
   441         for ( int i = 0; i < sx.length; i++ )
       
   442             {
       
   443             if ( sx[ i ].contains( CSSHandler.SEPARATOR ) )
       
   444                 {
       
   445                 // Check if single color's value is integer
       
   446                 Short valueType = iValueTypeResolver.getValue( Short
       
   447                         .valueOf( sx[ i ].substring( 0, sx[ i ]
       
   448                                 .indexOf( CSSHandler.SEPARATOR ) ) ) );
       
   449 
       
   450                 if ( valueType.intValue() != ValueTypeResolver.E_NUMBER )
       
   451                     {
       
   452                     throw new ODTException(
       
   453                             "Error in DOM/style data externalization: "
       
   454                                     + "RGB Values: R, G or B not interger" );
       
   455                     }
       
   456                 String redGreenBlue = sx[ i ].substring( sx[ i ]
       
   457                         .indexOf( CSSHandler.SEPARATOR ) + 1, sx[ i ]
       
   458                         .length() );
       
   459                 Integer rgbValue = Integer.valueOf( redGreenBlue );
       
   460                 ix[ i ] = rgbValue.intValue();
       
   461                 }
       
   462             else
       
   463                 {
       
   464                 throw new ODTException(
       
   465                         "Error in DOM/style data externalization: "
       
   466                                 + "RGB Values: can't resolve value type" );
       
   467                 }
       
   468             }
       
   469         return new Color( ix[ 0 ], ix[ 1 ], ix[ 2 ] );
       
   470         }
       
   471 
       
   472     /**
       
   473      * Parses the Value Type from Value.
       
   474      *
       
   475      * @param aAttrValue The attribute value
       
   476      *
       
   477      * @return Parsed value as a string
       
   478      *
       
   479      * @throws IOException Signals that an I/O exception has occurred.
       
   480      * @throws ODTException
       
   481      */
       
   482     private String parseAttrValue( String aAttrValue, PropertyValue aPropValue )
       
   483         throws IOException, ODTException
       
   484         {
       
   485         if ( aAttrValue.length() > 0 )
       
   486             {
       
   487             if ( aAttrValue.contains( "|" ) )
       
   488                 {
       
   489                 String type = aAttrValue
       
   490                         .substring( 0, aAttrValue.indexOf( '|' ) );
       
   491                 String value = aAttrValue.substring(
       
   492                         aAttrValue.indexOf( '|' ) + 1, aAttrValue.length() );
       
   493 
       
   494                 Short lexicalUnit = Short.valueOf( type );
       
   495                 Short primitiveValueType =
       
   496                         iValueTypeResolver.getValue( lexicalUnit );
       
   497 
       
   498                 switch ( primitiveValueType.intValue() )
       
   499                     {
       
   500                     case ValueTypeResolver.E_NUMBER:
       
   501                         double doubleValueInteger = Double.valueOf( value ).doubleValue();
       
   502                         aPropValue.setRealValue( doubleValueInteger,
       
   503                                                  primitiveValueType.shortValue() );
       
   504                         break;
       
   505                     case ValueTypeResolver.E_UNIT_VALUE:
       
   506                     case ValueTypeResolver.E_PERCENTAGE:
       
   507                     case ValueTypeResolver.E_EMS:
       
   508                     case ValueTypeResolver.E_EXS:
       
   509                     case ValueTypeResolver.E_PX:
       
   510                     case ValueTypeResolver.E_CM:
       
   511                     case ValueTypeResolver.E_MM:
       
   512                     case ValueTypeResolver.E_IN:
       
   513                     case ValueTypeResolver.E_PT:
       
   514                     case ValueTypeResolver.E_PC:
       
   515                     case ValueTypeResolver.E_DEG:
       
   516                     case ValueTypeResolver.E_RAD:
       
   517                     case ValueTypeResolver.E_GRAD:
       
   518                     case ValueTypeResolver.E_MS:
       
   519                     case ValueTypeResolver.E_S:
       
   520                     case ValueTypeResolver.E_HZ:
       
   521                     case ValueTypeResolver.E_KHZ:
       
   522                         double doubleValuePercentage = Double.valueOf( value ).doubleValue();
       
   523                         aPropValue.setRealValue( doubleValuePercentage,
       
   524                                                  primitiveValueType.shortValue() );
       
   525                         break;
       
   526                     case ValueTypeResolver.E_IDENT:
       
   527                     case ValueTypeResolver.E_STRING:
       
   528                     case ValueTypeResolver.E_URI:
       
   529                     case ValueTypeResolver.E_ATTR:
       
   530                         aPropValue.setString( new String( value ),
       
   531                                 primitiveValueType.shortValue() );
       
   532                         break;
       
   533                     case ValueTypeResolver.E_RGB_COLOR:
       
   534                         Color color = parseColorFromString(value);
       
   535                         aPropValue.setRgbValue( color );
       
   536                         break;
       
   537                     default:
       
   538                         break;
       
   539                     }
       
   540 
       
   541                 return value;
       
   542                 }
       
   543             return aAttrValue;
       
   544             }
       
   545         return aAttrValue;
       
   546         }
       
   547 
       
   548     /**
       
   549      * Externalize a list of property values.
       
   550      *
       
   551      * @param aNode the a node
       
   552      * @param aAttrList the a attr list
       
   553      *
       
   554      * @return true, if property is inherited
       
   555      *
       
   556      * @throws IOException if data output stream can not be written
       
   557      * @throws ODTException if there is an error with externalizing property values
       
   558      */
       
   559     private boolean externalizePropertyValueList( Node aNode, NamedNodeMap aAttrList )
       
   560         throws IOException, ODTException
       
   561         {
       
   562         PropertyValueList valueList = new PropertyValueList( iStringPool );
       
   563 
       
   564         boolean isInherited = false;
       
   565         String name = null;
       
   566         String value = null;
       
   567 
       
   568         for ( int i = 0; i < aAttrList.getLength(); i++ )
       
   569             {
       
   570             Node node = aAttrList.item( i );
       
   571 
       
   572             if ( nodeType( node ) == ATTRIBUTE &&
       
   573                  !node.getNodeName().equals( CSSDOMProcessor.STRING_PSEUDOCLASS ) )
       
   574                 {
       
   575                 String attrName = node.getNodeName();
       
   576                 String attrValue = node.getNodeValue();
       
   577 
       
   578                 if( attrName.equals( CSSDOMProcessor.STRING_NAME ) &&
       
   579                     name == null )
       
   580                     {
       
   581                     name = attrValue;
       
   582                     }
       
   583                     else if( attrName.startsWith( CSSDOMProcessor.STRING_VALUE ) )
       
   584                     {
       
   585                     value = attrValue;
       
   586 
       
   587                     // Checking if property is inherited.
       
   588                     // This emulates the behavior of the Symbian side implementation
       
   589                     // where this is true in following cases:
       
   590                     // 1. Value equals "inherited"
       
   591                     // 2. Property is inheritable and the element can inherit properties
       
   592                     //
       
   593                     // This means that also some properties that aren't actually
       
   594                     // inherited, are also set with value isIherited == "true"
       
   595                     isInherited = iCSSDOMProsessor.canInherit( (Element) aNode, name, value );
       
   596 
       
   597                     PropertyValue propValue = valueList.newItem();
       
   598                     parseAttrValue( value, propValue );
       
   599                     }
       
   600                 else
       
   601                     {
       
   602                     throw new ODTException( "Error in DOM/style data externalization: " +
       
   603                     		"Property values" );
       
   604                     }
       
   605                 }
       
   606             }
       
   607 
       
   608         if( name != null &&
       
   609             value != null )
       
   610             {
       
   611             // Write property name
       
   612             int nameRef = iStringPool.addString( name );
       
   613             iODTDos.writeInt16( nameRef );
       
   614 
       
   615             // Externalize the property value list to the stream
       
   616             valueList.externalize( iODTDos );
       
   617             }
       
   618         else
       
   619             {
       
   620             throw new ODTException( "Error in DOM/style data externalization: " +
       
   621             		"Property values" );
       
   622             }
       
   623         return isInherited;
       
   624         }
       
   625 
       
   626     /**
       
   627      * Count element nodes in a node list.
       
   628      * @param aList Node list
       
   629      * @param aNodeType Node type to count
       
   630      * @return Count of found nodes
       
   631      */
       
   632     private static int countNodes( NodeList aList )
       
   633         {
       
   634         int count = 0;
       
   635         for( int i = 0; i < aList.getLength(); i++ )
       
   636             {
       
   637             // Exclude elements that are style properties
       
   638             if( nodeType( aList.item( i ) ) == NODE )
       
   639                 {
       
   640                 count++;
       
   641                 }
       
   642             }
       
   643 
       
   644         return count;
       
   645         }
       
   646 
       
   647     /**
       
   648      * Count attributes in a named node map.
       
   649      * @param aList Node map
       
   650      * @param aNodeType Node type to count
       
   651      * @return Count of found nodes
       
   652      */
       
   653     private static int countAttributes( NamedNodeMap aList )
       
   654         {
       
   655         int count = 0;
       
   656         for( int i = 0; i < aList.getLength(); i++ )
       
   657             {
       
   658             if( nodeType( aList.item( i ) ) == ATTRIBUTE )
       
   659                 {
       
   660                 count++;
       
   661                 }
       
   662             }
       
   663 
       
   664         return count;
       
   665         }
       
   666 
       
   667     /**
       
   668      * Count properties in a node list.
       
   669      * @param aList Node list
       
   670      * @param aNodeType Node type to count
       
   671      * @return Count of found nodes
       
   672      */
       
   673     private static int countProperties( NodeList aList )
       
   674         {
       
   675         int count = 0;
       
   676         for( int i = 0; i < aList.getLength(); i++ )
       
   677             {
       
   678             // Include only elements that are style properties
       
   679             if( nodeType( aList.item( i ) ) == PROPERTY )
       
   680                 {
       
   681                 count++;
       
   682                 }
       
   683             }
       
   684 
       
   685         return count;
       
   686         }
       
   687 
       
   688     /**
       
   689      * Resolve node type. Possible types: NODE, ATTRIBUTE or PROPERTY
       
   690      * @param aItem Node to resolve
       
   691      * @return Type of the node. If the type can not be determined, UNKNOWN is returned
       
   692      */
       
   693     private static int nodeType( Node aItem )
       
   694         {
       
   695         int type = UNKNOWN;
       
   696 
       
   697         // Element that is not a style property element
       
   698         if( aItem.getNodeType() == Node.ELEMENT_NODE &&
       
   699             !aItem.getNodeName().equals( CSSDOMProcessor.STRING_PROPERTY ) )
       
   700             {
       
   701             type = NODE;
       
   702             }
       
   703         // Attribute nodes
       
   704         else if( aItem.getNodeType() == Node.ATTRIBUTE_NODE )
       
   705             {
       
   706             type = ATTRIBUTE;
       
   707             }
       
   708         // Style property element
       
   709         else if( aItem.getNodeType() == Node.ELEMENT_NODE &&
       
   710                  aItem.getNodeName().equals( CSSDOMProcessor.STRING_PROPERTY ) )
       
   711             {
       
   712             type = PROPERTY;
       
   713             }
       
   714 
       
   715         return type;
       
   716         }
       
   717 
       
   718     }