KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > ozoneDB > xml > dom > ElementImpl


1 /**
2  * org/ozone-db/xml/dom/ElementImpl.java
3  *
4  * The contents of this file are subject to the OpenXML Public
5  * License Version 1.0; you may not use this file except in compliance
6  * with the License. You may obtain a copy of the License at
7  * http://www.openxml.org/license.html
8  *
9  * THIS SOFTWARE IS DISTRIBUTED ON AN "AS IS" BASIS WITHOUT WARRANTY
10  * OF ANY KIND, EITHER EXPRESSED OR IMPLIED. THE INITIAL DEVELOPER
11  * AND ALL CONTRIBUTORS SHALL NOT BE LIABLE FOR ANY DAMAGES AS A
12  * RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
13  * DERIVATIVES. SEE THE LICENSE FOR THE SPECIFIC LANGUAGE GOVERNING
14  * RIGHTS AND LIMITATIONS UNDER THE LICENSE.
15  *
16  * The Initial Developer of this code under the License is Assaf Arkin.
17  * Portions created by Assaf Arkin are Copyright (C) 1998, 1999.
18  * All Rights Reserved.
19  */

20
21 /**
22  * Changes for Persistent DOM running with ozone are
23  * Copyright 1999 by SMB GmbH. All rights reserved.
24  */

25
26 package org.ozoneDB.xml.dom;
27
28 import java.util.*;
29 import java.io.*;
30 import org.w3c.dom.*;
31 import org.ozoneDB.*;
32
33
34 /**
35  * The most common node type, {@link org.w3c.dom.Element} inherits the generic
36  * {@link Node} interface and adds support for retrieving and setting attributes
37  * either as nodes or as strings.
38  * <P>
39  * Notes:
40  * <OL>
41  * <LI>Node type is {@link org.w3c.dom.Node#ELEMENT_NODE}
42  * <LI>Node supports childern
43  * <LI>Node has no value
44  * <LI>Node has attributes
45  * </OL>
46  * <P>
47  * To speed up implementation, all attributes are implemented as double-linked
48  * list implemented using {@link NodeImpl#_parent}, {@link NodeImpl#_nextNode} and
49  * {@link NodeImpl#_prevNode}. This support is provided to through {@link
50  * #getNamedAttr}, {@link #appendAttr} and {@link #removeAttr} methods.
51  *
52  *
53  * @version $Revision: 1.2 $ $Date: 2003/11/20 23:18:42 $
54  * @author <a HREF="mailto:arkin@trendline.co.il">Assaf Arkin</a>
55  * @see org.w3c.dom.Element
56  * @see org.w3c.dom.Attr
57  * @see org.w3c.dom.NamedNodeMap
58  * @see AttrImpl
59  */

60 public class ElementImpl extends NodeImpl implements ElementProxy, Externalizable {
61
62     final static long serialVersionUID = 1;
63
64
65     public Node getNamedItemNS( java.lang.String JavaDoc namespaceURI, java.lang.String JavaDoc localName ) {
66         throw new DOMExceptionImpl( DOMException.NOT_SUPPORTED_ERR,
67                 "Element.getNamedItemNS(): ozone's persistent DOM doesn't support DOM level 2 yet." );
68     }
69
70
71     public Node setNamedItemNS( Node arg ) throws DOMException {
72         throw new DOMExceptionImpl( DOMException.NOT_SUPPORTED_ERR,
73                 "Element.setNamedItemNS(): ozone's persistent DOM doesn't support DOM level 2 yet." );
74     }
75
76
77     public Node removeNamedItemNS( java.lang.String JavaDoc namespaceURI, java.lang.String JavaDoc localName ) throws DOMException {
78         throw new DOMExceptionImpl( DOMException.NOT_SUPPORTED_ERR,
79                 "Element.removeNamedItemNS(): ozone's persistent DOM doesn't support DOM level 2 yet." );
80     }
81
82
83     public Attr getAttributeNodeNS( java.lang.String JavaDoc namespaceURI, java.lang.String JavaDoc localName ) {
84         throw new DOMExceptionImpl( DOMException.NOT_SUPPORTED_ERR,
85                 "Element.getAttributeNodeNS(): ozone's persistent DOM doesn't support DOM level 2 yet." );
86     }
87
88
89     public Attr setAttributeNodeNS( Attr newAttr ) throws DOMException {
90         throw new DOMExceptionImpl( DOMException.NOT_SUPPORTED_ERR,
91                 "Element.setAttributeNodeNS(): ozone's persistent DOM doesn't support DOM level 2 yet." );
92     }
93
94
95     public java.lang.String JavaDoc getAttributeNS( java.lang.String JavaDoc namespaceURI, java.lang.String JavaDoc localName ) {
96         throw new DOMExceptionImpl( DOMException.NOT_SUPPORTED_ERR,
97                 "Element.getAttributeNS(): ozone's persistent DOM doesn't support DOM level 2 yet." );
98     }
99
100
101     public void setAttributeNS( java.lang.String JavaDoc namespaceURI, java.lang.String JavaDoc qualifiedName, java.lang.String JavaDoc value )
102             throws DOMException {
103         throw new DOMExceptionImpl( DOMException.NOT_SUPPORTED_ERR,
104                 "Element.setAttributeNS(): ozone's persistent DOM doesn't support DOM level 2 yet." );
105     }
106
107
108     public void removeAttributeNS( java.lang.String JavaDoc namespaceURI, java.lang.String JavaDoc localName ) throws DOMException {
109         throw new DOMExceptionImpl( DOMException.NOT_SUPPORTED_ERR,
110                 "Element.removeAttributeNS(): ozone's persistent DOM doesn't support DOM level 2 yet." );
111     }
112
113
114     public NodeList getElementsByTagNameNS( java.lang.String JavaDoc namespaceURI, java.lang.String JavaDoc localName ) {
115         throw new DOMExceptionImpl( DOMException.NOT_SUPPORTED_ERR,
116                 "Element.getNamedItemNS(): ozone's persistent DOM doesn't support DOM level 2 yet." );
117     }
118
119
120     public boolean hasAttributes() {
121         throw new DOMExceptionImpl( DOMException.NOT_SUPPORTED_ERR,
122                 "Element.hasAttributes(): ozone's persistent DOM doesn't support DOM level 2 yet." );
123     }
124
125
126     public boolean hasAttribute( String JavaDoc name ) {
127         throw new DOMExceptionImpl( DOMException.NOT_SUPPORTED_ERR,
128                 "Element.hasAttribute(): ozone's persistent DOM doesn't support DOM level 2 yet." );
129     }
130
131
132     public boolean hasAttributeNS( String JavaDoc namespaceURI, String JavaDoc localname ) {
133         throw new DOMExceptionImpl( DOMException.NOT_SUPPORTED_ERR,
134                 "Element.hasAttributeNS(): ozone's persistent DOM doesn't support DOM level 2 yet." );
135     }
136
137
138     public final short getNodeType() {
139         return ELEMENT_NODE;
140     }
141
142
143     public final Enumeration elements() {
144         return null;
145     }
146
147
148     public void setFirstAttr( Attr attribute ) {
149         _firstAttr = (AttrProxy)attribute;
150     }
151
152
153     public void setLastAttr( Attr attribute ) {
154         _lastAttr = (AttrProxy)attribute;
155     }
156
157
158     public void setAttrCount( int count ) {
159         _attrCount = count;
160     }
161
162
163     /**
164      * Returns the name of the tag, same as calling {@link #getNodeName}.
165      * In XML documents, the return value preserves case. In HTML documents,
166      * the return value is always upper case regardless of the original value.
167      *
168      * @return Tag name
169      */

170     public final String JavaDoc getTagName() {
171         return getNodeName();
172     }
173
174
175     public final void setNodeValue( String JavaDoc value ) {
176         throw new DOMExceptionImpl( DOMException.NO_DATA_ALLOWED_ERR, "This node type does not support values." );
177     }
178
179
180     /**
181      * Returns a list of elements extracted based on their tag name (or all of
182      * them if the tag name is "*"). The returned list is a snapshot of the
183      * element's contents at the time of calling. Subsequent updates to the
184      * element are not reflected in the list. This might result in inaccuracies
185      * when working from multiple threads.
186      *
187      * @param tagName The element tag name to look for or "*" for all elements
188      * @return A snapshot of the named elements contained within this element
189      */

190     public synchronized final NodeList getElementsByTagName( String JavaDoc tagName ) {
191         // The full implementation can be found in ElementListImpl
192
return new org.ozoneDB.xml.dom.ElementListImpl( this, tagName );
193     }
194
195
196     public synchronized final void normalize() {
197         Node node;
198         Node next;
199
200         // Run through all child nodes of this element. If a particular child
201
// is an Element, normalize it. If a particular child is a Text and is
202
// followed by a second Text node, concatenate the data from the second
203
// to the first and remove the second node.
204
node = getFirstChild();
205         while (node != null) {
206             if (node instanceof ElementProxy) {
207                 node.normalize();
208             } else {
209                 if (node instanceof TextProxy) {
210                     next = node.getNextSibling();
211                     while (next != null && next instanceof TextProxy) {
212                         ((TextProxy)node).appendData( ((TextProxy)next).getData() );
213                         removeChild( next );
214                         next = node.getNextSibling();
215                     }
216                 }
217             }
218             node = node.getNextSibling();
219         }
220     }
221
222
223     public final NamedNodeMap getAttributes() {
224         // This is a NamedNodeMap of all its attributes.
225
// return this;
226
return (NamedNodeMap)self();
227     }
228
229
230     public synchronized final String JavaDoc getAttribute( String JavaDoc name ) {
231         AttrProxy attr;
232
233         // Look for the named attribute and return it's value.
234
attr = (AttrProxy)getNamedAttr( name );
235         if (attr == null) {
236             return "";
237         }
238         return attr.getValue();
239     }
240
241
242     public synchronized final void setAttribute( String JavaDoc name, String JavaDoc value ) throws DOMException {
243         AttrProxy attr;
244
245         if (isReadOnly()) {
246             throw new DOMExceptionImpl( DOMException.NO_MODIFICATION_ALLOWED_ERR );
247         }
248         // If attribute value is null, might as well remove attribute. This will
249
// either save space, or return the default value instead.
250
if (value == null) {
251             removeAttribute( name );
252         } else {
253             try {
254                 // Get the named attribute and change it's value. If the attribute
255
// does not exist, create a new attribute by that name and add it.
256
// Call setValue() to assure correct behavior.
257
attr = (AttrProxy)getNamedAttr( name );
258                 if (attr == null) {
259                     attr = (AttrProxy)database().createObject( AttrImpl.class.getName() );
260                     attr.init( _ownerDocument, name, "" );
261                     appendAttr( attr );
262                 }
263                 attr.setValue( value );
264             } catch (Exception JavaDoc except) {
265                 throw new DOMExceptionImpl( DOMExceptionImpl.PDOM_ERR, except.getMessage() );
266             }
267         }
268     }
269
270
271     public synchronized final void removeAttribute( String JavaDoc name ) {
272         AttrProxy attr;
273
274         attr = (AttrProxy)getNamedAttr( name );
275         if (attr != null) {
276             removeAttr( attr );
277         }
278     }
279
280
281     public final Attr getAttributeNode( String JavaDoc name ) {
282         return getNamedAttr( name );
283     }
284
285
286     public synchronized final Attr setAttributeNode( Attr newAttr ) throws DOMException {
287         AttrProxy oldAttr;
288
289         if (isReadOnly()) {
290             throw new DOMExceptionImpl( DOMException.NO_MODIFICATION_ALLOWED_ERR );
291         }
292         if (newAttr == null || !(newAttr instanceof AttrProxy)) {
293             throw new DOMExceptionImpl( DOMException.WRONG_DOCUMENT_ERR );
294         }
295         // Note: getParentNode() will return null.
296
if (newAttr.getParentNode() != null) {
297             throw new DOMExceptionImpl( DOMException.INUSE_ATTRIBUTE_ERR );
298         }
299         synchronized (newAttr) {
300             oldAttr = (AttrProxy)getNamedAttr( newAttr.getName() );
301             if (oldAttr != null) {
302                 removeAttr( oldAttr );
303             }
304             appendAttr( (AttrProxy)newAttr );
305         }
306         return oldAttr;
307     }
308
309
310     public synchronized final Attr removeAttributeNode( Attr oldAttr ) {
311         if (isReadOnly()) {
312             throw new DOMExceptionImpl( DOMException.NO_MODIFICATION_ALLOWED_ERR );
313         }
314         if (!(oldAttr instanceof Attr)) {
315             throw new DOMExceptionImpl( DOMException.HIERARCHY_REQUEST_ERR,
316                     "Node is not an attribute compatible with this element." );
317         }
318         oldAttr = removeAttr( (AttrProxy)oldAttr );
319         if (oldAttr == null) {
320             throw new DOMExceptionImpl( DOMException.NOT_FOUND_ERR );
321         }
322         return oldAttr;
323     }
324
325
326     public synchronized final Node getNamedItem( String JavaDoc name ) {
327         return getNamedAttr( name );
328     }
329
330
331     public final Node setNamedItem( Node arg ) throws DOMException {
332         if (!(arg instanceof AttrProxy)) {
333             throw new DOMExceptionImpl( DOMException.HIERARCHY_REQUEST_ERR,
334                     "Node is not an attribute compatible with this element." );
335         }
336         return setAttributeNode( (AttrProxy)arg );
337     }
338
339
340     public synchronized final Node removeNamedItem( String JavaDoc name ) throws DOMException {
341         AttrProxy attr;
342
343         attr = (AttrProxy)getNamedAttr( name );
344         if (attr != null) {
345             removeAttr( attr );
346             return attr;
347         } else {
348             return null;
349         }
350     }
351
352
353     public synchronized final Node item( int index ) {
354         AttrProxy attr;
355
356         attr = _firstAttr;
357         while (attr != null && index > 0) {
358             // Note: getNextSibling() will return null.
359
attr = (AttrProxy)attr.getNextSibling();
360             --index;
361         }
362         return attr;
363     }
364
365
366     public int getLength() {
367         return _attrCount;
368     }
369
370
371     public synchronized boolean equals( Object JavaDoc other ) {
372         ElementProxy otherX;
373         AttrProxy attr;
374         boolean equal;
375
376         // If both objects are the same, return true. If one is null, or they
377
// do not belong to the same class, return false. Equality is not
378
// tested across different DOMs or different ClassLoaders.
379
if (this == other) {
380             return true;
381         }
382         if (other == null || !(other instanceof Element)) {
383             return false;
384         }
385         if (!super.equals( other )) {
386             return false;
387         }
388         synchronized (other) {
389             otherX = (ElementProxy)other;
390             equal = _attrCount == otherX.getLength();
391             if (equal) {
392                 // Test for attributes first, this is the faster test and
393
// can tell elements apart quite easily. Since attributes might
394
// be out of sequence, retrieve attributes by name not by sequence.
395
// This test is recursive to some degree.
396
attr = _firstAttr;
397                 while (equal && attr != null) {
398                     equal = otherX.getNamedAttr( attr.getNodeName() ) != null && otherX.getNamedAttr(
399                             attr.getNodeName() ).equals( attr );
400                     // Note: getNextSibling() will return null.
401
attr = (AttrProxy)attr.getNextSibling();
402                 }
403             }
404         }
405         return equal;
406     }
407
408
409     public final Object JavaDoc clone() {
410         ElementProxy clone = null;
411         try {
412             clone = (ElementProxy)_ownerDocument.createElement( getNodeName() );
413             cloneInto( clone, true );
414         } catch (Exception JavaDoc except) {
415             throw new DOMExceptionImpl( DOMExceptionImpl.PDOM_ERR, except.getMessage() );
416         }
417         return clone;
418     }
419
420
421     public final Node cloneNode( boolean deep ) {
422         ElementProxy clone = null;
423         try {
424             clone = (ElementProxy)_ownerDocument.createElement( getNodeName() );
425             cloneInto( clone, deep );
426         } catch (Exception JavaDoc except) {
427             throw new DOMExceptionImpl( DOMExceptionImpl.PDOM_ERR, except.getMessage() );
428         }
429         return clone;
430     }
431
432
433     public String JavaDoc toString() {
434         String JavaDoc name;
435
436         name = getTagName();
437         if (name.length() > 32) {
438             name = name.substring( 0, 32 ) + "..";
439         }
440         return "Element node: [" + name + "] (" + getChildCount() + " nodes)";
441     }
442
443
444     public synchronized void cloneInto( NodeProxy into, boolean deep ) {
445         AttrProxy attr;
446         ElementProxy intoX;
447
448         super.cloneInto( into, deep );
449
450         intoX = (ElementProxy)into;
451         // Duplicate all attributes . Note that attributes are duplicated with deep
452
// cloning, since an attribute might contain Text and EntityReference nodes.
453
intoX.setFirstAttr( null );
454         intoX.setLastAttr( null );
455         intoX.setAttrCount( 0 );
456         attr = _firstAttr;
457         while (attr != null) {
458             intoX.appendAttr( (AttrProxy)attr.cloneNode( true ) );
459             // Note: getNextSibling() will return null.
460
attr = (AttrProxy)attr.getNextSibling();
461         }
462     }
463
464
465     protected boolean supportsChildern() {
466         return true;
467     }
468
469
470     /**
471      * Returns the named attribute or null if attribute not found.
472      *
473      * @param name The name of the attribute to return
474      * @return The named attribute or null
475      */

476     public synchronized final Attr getNamedAttr( String JavaDoc name ) {
477         AttrProxy attr;
478
479         attr = _firstAttr;
480         while (attr != null) {
481             if (attr.getName().equals( name )) {
482                 return attr;
483             }
484             // Note: getNextSibling() will return null.
485
attr = (AttrProxy)attr.getNextSibling();
486         }
487         return null;
488     }
489
490
491     /**
492      * Append <TT>newAttr</TT> as the last attribute of this element.
493      * If <TT>newAttr</TT> is not an attribute of this DOM, or is already in use
494      * by some element, an exception is thrown.
495      *
496      * @param newAttr The new attribute to add
497      * @return The newly added attribute
498      * @throws org.w3c.dom.DOMException <TT>NO_MODIFICATION_ALLOWED_ERR</TT>
499      * Node is read-only and cannot be modified
500      * @throws org.w3c.dom.DOMException <TT>WRONG_DOCUMENT_ERR</TT>
501      * <TT>newAttr</TT> is not an attribute in this DOM
502      * @throws org.w3c.dom.DOMException <TT>INUSE_ATTRIBUTE_ERR</TT>
503      * <TT>newAttr</TT> is already in use by some other element
504      */

505     public synchronized final AttrProxy appendAttr( AttrProxy newAttr ) {
506         // Make sure the node is not read-only and the attribute can be added to it.
507
if (isReadOnly()) {
508             throw new DOMExceptionImpl( DOMException.NO_MODIFICATION_ALLOWED_ERR );
509         }
510         if (newAttr == null) {
511             throw new DOMExceptionImpl( DOMException.WRONG_DOCUMENT_ERR,
512                     "Attribute does not belong to same document as this element." );
513         }
514         if (newAttr.getParentNode() == this) {
515             return newAttr;
516         }
517         if (newAttr.getParentNode() != null) {
518             throw new DOMExceptionImpl( DOMException.INUSE_ATTRIBUTE_ERR );
519         }
520
521
522         // We're going to mess with this attribute, so make sure no other thread
523
// is touching it
524
synchronized (newAttr) {
525             newAttr.setParentNode( this );
526             newAttr.setOwnerDocument( getOwnerDocument() );
527
528             // If the list has no end (it is empty) then newAttr is added as the
529
// only attribute in it.
530
if (_lastAttr == null) {
531                 _lastAttr = newAttr;
532                 _firstAttr = newAttr;
533                 newAttr.setPreviousSibling( null );
534                 newAttr.setNextSibling( null );
535             } else {
536                 // newAttr becomes the new end of the list, adjusting the previous
537
// last attribute.
538
_lastAttr.setNextSibling( newAttr );
539                 newAttr.setPreviousSibling( _lastAttr );
540                 newAttr.setNextSibling( null );
541                 _lastAttr = newAttr;
542             }
543             // Keep this count accurate at all times.
544
++_attrCount;
545         }
546         return newAttr;
547     }
548
549
550     /**
551      * Remove <TT>oldAttr</TT> from this element. If <TT>oldAttr</TT> is not an
552      * attribute of this element, an exception is thrown.
553      *
554      * @param oldAttr The attribute to remove
555      * @return The removed attribute
556      * @throws org.w3c.dom.DOMException <TT>NO_MODIFICATION_ALLOWED_ERR</TT>
557      * Node is read-only and cannot be modified
558      * @throws org.w3c.dom.DOMException <TT>NOT_FOUND_ERR</TT>
559      * <TT>oldAttr</TT> is not an attribute of this element
560      */

561     public synchronized final AttrProxy removeAttr( AttrProxy oldAttr ) throws DOMException {
562
563         // Make sure the element is not read-only and the attribute belonds to it.
564
if (isReadOnly()) {
565             throw new DOMExceptionImpl( DOMException.NO_MODIFICATION_ALLOWED_ERR );
566         }
567         // Note: getParentNode() will return null.
568
if (oldAttr == null || !((OzoneProxy)oldAttr.getParentNode()).remoteID().equals( container().id() )) {
569             throw new DOMExceptionImpl( DOMException.NOT_FOUND_ERR, "Not an attribute of this element." );
570         }
571
572         // We're going to mess with this attribute node, so make sure no other
573
// thread is touching it
574
synchronized (oldAttr) {
575             // Attribute becomes orphan. It is no longer first or last attribute of
576
// this element. Removed from linked list.
577
oldAttr.setParentNode( null );
578             if (_firstAttr == oldAttr) {
579                 _firstAttr = (AttrProxy)oldAttr.getNextSibling();
580             }
581             if (_lastAttr == oldAttr) {
582                 _lastAttr = (AttrProxy)oldAttr.getPreviousSibling();
583             }
584             if (oldAttr.getPreviousSibling() != null) {
585                 ((NodeProxy)oldAttr.getPreviousSibling()).setNextSibling( oldAttr.getNextSibling() );
586             }
587             if (oldAttr.getNextSibling() != null) {
588                 ((NodeProxy)oldAttr.getNextSibling()).setPreviousSibling( oldAttr.getPreviousSibling() );
589             }
590             oldAttr.setPreviousSibling( null );
591             oldAttr.setNextSibling( null );
592             // Keep this count accurate at all times.
593
--_attrCount;
594         }
595         return oldAttr;
596     }
597
598
599     /**
600      * Constructor requires only owner document and tag name of element.
601      * Tag name is case sensitive for XML, but converted to upper case for
602      * HTML documents.
603      *
604      * @param owner Owner document of this element
605      * @param name The tag name of the element
606      */

607     public ElementImpl( DocumentImpl owner, String JavaDoc name ) {
608         super( owner, name, null, true );
609         // Make sure that all element tag names are converted to upper case
610
// for some documents (HTML).
611
}
612
613
614     public ElementImpl() {
615         super();
616     }
617
618
619     public void init( NodeProxy owner, Dictionary dictionary ) {
620     // System.out.println ("ElementImpl.init()");
621
}
622
623
624     public void onDelete() {
625         // remove all Attributes of this Element-Node
626
deleteAllChildern( _firstAttr );
627     }
628
629
630     private void deleteAllChildern( Node node ) {
631         Node dummyNode;
632         while (node != null) {
633             if (node.hasChildNodes()) {
634                 deleteAllChildern( node.getFirstChild() );
635             }
636             dummyNode = node.getNextSibling();
637             database().deleteObject( (OzoneRemote)node );
638             node = dummyNode;
639         }
640     }
641
642
643     /** */
644     public void writeExternal( ObjectOutput out ) throws IOException {
645         super.writeExternal( out );
646         out.writeByte( (byte)_attrCount );
647         if (_attrCount > 0) {
648             out.writeObject( _firstAttr );
649             out.writeObject( _lastAttr );
650         }
651     }
652
653
654     /** */
655     public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException JavaDoc {
656         super.readExternal( in );
657         _attrCount = in.readByte();
658         if (_attrCount > 0) {
659             _firstAttr = (AttrProxy)in.readObject();
660             _lastAttr = (AttrProxy)in.readObject();
661         } else {
662             _firstAttr = null;
663             _lastAttr = null;
664         }
665     }
666
667
668     /**
669      * The attributes of this element are arranged in a doubly linked lists.
670      * This reference identifies the first attribute in the list.
671      */

672     private AttrProxy _firstAttr;
673
674     /**
675      * The attributes of this element are arranged in a doubly linked lists.
676      * This reference identifies the last attribute in the list.
677      */

678     private AttrProxy _lastAttr;
679
680     /**
681      * Counts how many attributes belong to this element.
682      */

683     private int _attrCount;
684
685 }
686
Popular Tags