KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xerces > util > XMLAttributesImpl


1 /*
2  * Copyright 2000-2002,2004 The Apache Software Foundation.
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 org.apache.xerces.util;
18
19 import org.apache.xerces.xni.Augmentations;
20 import org.apache.xerces.xni.QName;
21 import org.apache.xerces.xni.XMLAttributes;
22
23 /**
24  * The XMLAttributesImpl class is an implementation of the XMLAttributes
25  * interface which defines a collection of attributes for an element.
26  * In the parser, the document source would scan the entire start element
27  * and collect the attributes. The attributes are communicated to the
28  * document handler in the startElement method.
29  * <p>
30  * The attributes are read-write so that subsequent stages in the document
31  * pipeline can modify the values or change the attributes that are
32  * propogated to the next stage.
33  *
34  * @see org.apache.xerces.xni.XMLDocumentHandler#startElement
35  *
36  * @author Andy Clark, IBM
37  * @author Elena Litani, IBM
38  * @author Michael Glavassevich, IBM
39  *
40  * @version $Id: XMLAttributesImpl.java,v 1.26 2004/03/25 04:03:22 mrglavas Exp $
41  */

42 public class XMLAttributesImpl
43     implements XMLAttributes {
44
45     //
46
// Constants
47
//
48

49     /** Default table size. */
50     protected static final int TABLE_SIZE = 101;
51     
52     /**
53      * Threshold at which an instance is treated
54      * as a large attribute list.
55      */

56     protected static final int SIZE_LIMIT = 20;
57     
58     //
59
// Data
60
//
61

62     // features
63

64     /** Namespaces. */
65     protected boolean fNamespaces = true;
66
67     // data
68

69     /**
70      * Usage count for the attribute table view.
71      * Incremented each time all attributes are removed
72      * when the attribute table view is in use.
73      */

74     protected int fLargeCount = 1;
75     
76     /** Attribute count. */
77     protected int fLength;
78
79     /** Attribute information. */
80     protected Attribute[] fAttributes = new Attribute[4];
81     
82     /**
83      * Hashtable of attribute information.
84      * Provides an alternate view of the attribute specification.
85      */

86     protected Attribute[] fAttributeTableView;
87     
88     /**
89      * Tracks whether each chain in the hash table is stale
90      * with respect to the current state of this object.
91      * A chain is stale if its state is not the same as the number
92      * of times the attribute table view has been used.
93      */

94     protected int[] fAttributeTableViewChainState;
95     
96     /**
97      * Actual number of buckets in the table view.
98      */

99     protected int fTableViewBuckets;
100     
101     /**
102      * Indicates whether the table view contains consistent data.
103      */

104     protected boolean fIsTableViewConsistent;
105
106     //
107
// Constructors
108
//
109

110     /** Default constructor. */
111     public XMLAttributesImpl() {
112         this(TABLE_SIZE);
113     }
114     
115     /**
116      * @param tableSize initial size of table view
117      */

118     public XMLAttributesImpl(int tableSize) {
119         fTableViewBuckets = tableSize;
120         for (int i = 0; i < fAttributes.length; i++) {
121             fAttributes[i] = new Attribute();
122         }
123     } // <init>()
124

125     //
126
// Public methods
127
//
128

129     /**
130      * Sets whether namespace processing is being performed. This state
131      * is needed to return the correct value from the getLocalName method.
132      *
133      * @param namespaces True if namespace processing is turned on.
134      *
135      * @see #getLocalName
136      */

137     public void setNamespaces(boolean namespaces) {
138         fNamespaces = namespaces;
139     } // setNamespaces(boolean)
140

141     //
142
// XMLAttributes methods
143
//
144

145     /**
146      * Adds an attribute. The attribute's non-normalized value of the
147      * attribute will have the same value as the attribute value until
148      * set using the <code>setNonNormalizedValue</code> method. Also,
149      * the added attribute will be marked as specified in the XML instance
150      * document unless set otherwise using the <code>setSpecified</code>
151      * method.
152      * <p>
153      * <strong>Note:</strong> If an attribute of the same name already
154      * exists, the old values for the attribute are replaced by the new
155      * values.
156      *
157      * @param name The attribute name.
158      * @param type The attribute type. The type name is determined by
159      * the type specified for this attribute in the DTD.
160      * For example: "CDATA", "ID", "NMTOKEN", etc. However,
161      * attributes of type enumeration will have the type
162      * value specified as the pipe ('|') separated list of
163      * the enumeration values prefixed by an open
164      * parenthesis and suffixed by a close parenthesis.
165      * For example: "(true|false)".
166      * @param value The attribute value.
167      *
168      * @return Returns the attribute index.
169      *
170      * @see #setNonNormalizedValue
171      * @see #setSpecified
172      */

173     public int addAttribute(QName name, String JavaDoc type, String JavaDoc value) {
174
175         int index;
176         if (fLength < SIZE_LIMIT) {
177             index = name.uri != null && !name.uri.equals("")
178                 ? getIndexFast(name.uri, name.localpart)
179                 : getIndexFast(name.rawname);
180
181             if (index == -1) {
182                 index = fLength;
183                 if (fLength++ == fAttributes.length) {
184                     Attribute[] attributes = new Attribute[fAttributes.length + 4];
185                     System.arraycopy(fAttributes, 0, attributes, 0, fAttributes.length);
186                     for (int i = fAttributes.length; i < attributes.length; i++) {
187                         attributes[i] = new Attribute();
188                     }
189                     fAttributes = attributes;
190                 }
191             }
192         }
193         else if (name.uri == null ||
194             name.uri.length() == 0 ||
195             (index = getIndexFast(name.uri, name.localpart)) == -1) {
196             
197             /**
198              * If attributes were removed from the list after the table
199              * becomes in use this isn't reflected in the table view. It's
200              * assumed that once a user starts removing attributes they're
201              * not likely to add more. We only make the view consistent if
202              * the user of this class adds attributes, removes them, and
203              * then adds more.
204              */

205             if (!fIsTableViewConsistent || fLength == SIZE_LIMIT) {
206                 prepareAndPopulateTableView();
207                 fIsTableViewConsistent = true;
208             }
209
210             int bucket = getTableViewBucket(name.rawname);
211         
212             // The chain is stale.
213
// This must be a unique attribute.
214
if (fAttributeTableViewChainState[bucket] != fLargeCount) {
215                 index = fLength;
216                 if (fLength++ == fAttributes.length) {
217                     Attribute[] attributes = new Attribute[fAttributes.length << 1];
218                     System.arraycopy(fAttributes, 0, attributes, 0, fAttributes.length);
219                     for (int i = fAttributes.length; i < attributes.length; i++) {
220                         attributes[i] = new Attribute();
221                     }
222                     fAttributes = attributes;
223                 }
224             
225                 // Update table view.
226
fAttributeTableViewChainState[bucket] = fLargeCount;
227                 fAttributes[index].next = null;
228                 fAttributeTableView[bucket] = fAttributes[index];
229             }
230             // This chain is active.
231
// We need to check if any of the attributes has the same rawname.
232
else {
233                 // Search the table.
234
Attribute found = fAttributeTableView[bucket];
235                 while (found != null) {
236                     if (found.name.rawname == name.rawname) {
237                         break;
238                     }
239                     found = found.next;
240                 }
241                 // This attribute is unique.
242
if (found == null) {
243                     index = fLength;
244                     if (fLength++ == fAttributes.length) {
245                         Attribute[] attributes = new Attribute[fAttributes.length << 1];
246                         System.arraycopy(fAttributes, 0, attributes, 0, fAttributes.length);
247                         for (int i = fAttributes.length; i < attributes.length; i++) {
248                             attributes[i] = new Attribute();
249                         }
250                         fAttributes = attributes;
251                     }
252                 
253                     // Update table view
254
fAttributes[index].next = fAttributeTableView[bucket];
255                     fAttributeTableView[bucket] = fAttributes[index];
256                 }
257                 // Duplicate. We still need to find the index.
258
else {
259                     index = getIndexFast(name.rawname);
260                 }
261             }
262         }
263         
264         // set values
265
Attribute attribute = fAttributes[index];
266         attribute.name.setValues(name);
267         attribute.type = type;
268         attribute.value = value;
269         attribute.nonNormalizedValue = value;
270         attribute.specified = false;
271             
272         // clear augmentations
273
attribute.augs.removeAllItems();
274
275         return index;
276
277     } // addAttribute(QName,String,XMLString)
278

279     /**
280      * Removes all of the attributes. This method will also remove all
281      * entities associated to the attributes.
282      */

283     public void removeAllAttributes() {
284         fLength = 0;
285     } // removeAllAttributes()
286

287     /**
288      * Removes the attribute at the specified index.
289      * <p>
290      * <strong>Note:</strong> This operation changes the indexes of all
291      * attributes following the attribute at the specified index.
292      *
293      * @param attrIndex The attribute index.
294      */

295     public void removeAttributeAt(int attrIndex) {
296         fIsTableViewConsistent = false;
297         if (attrIndex < fLength - 1) {
298             Attribute removedAttr = fAttributes[attrIndex];
299             System.arraycopy(fAttributes, attrIndex + 1,
300                 fAttributes, attrIndex, fLength - attrIndex - 1);
301             // Make the discarded Attribute object available for re-use
302
// by tucking it after the Attributes that are still in use
303
fAttributes[fLength-1] = removedAttr;
304         }
305         fLength--;
306     } // removeAttributeAt(int)
307

308     /**
309      * Sets the name of the attribute at the specified index.
310      *
311      * @param attrIndex The attribute index.
312      * @param attrName The new attribute name.
313      */

314     public void setName(int attrIndex, QName attrName) {
315         fAttributes[attrIndex].name.setValues(attrName);
316     } // setName(int,QName)
317

318     /**
319      * Sets the fields in the given QName structure with the values
320      * of the attribute name at the specified index.
321      *
322      * @param attrIndex The attribute index.
323      * @param attrName The attribute name structure to fill in.
324      */

325     public void getName(int attrIndex, QName attrName) {
326         attrName.setValues(fAttributes[attrIndex].name);
327     } // getName(int,QName)
328

329     /**
330      * Sets the type of the attribute at the specified index.
331      *
332      * @param attrIndex The attribute index.
333      * @param attrType The attribute type. The type name is determined by
334      * the type specified for this attribute in the DTD.
335      * For example: "CDATA", "ID", "NMTOKEN", etc. However,
336      * attributes of type enumeration will have the type
337      * value specified as the pipe ('|') separated list of
338      * the enumeration values prefixed by an open
339      * parenthesis and suffixed by a close parenthesis.
340      * For example: "(true|false)".
341      */

342     public void setType(int attrIndex, String JavaDoc attrType) {
343         fAttributes[attrIndex].type = attrType;
344     } // setType(int,String)
345

346     /**
347      * Sets the value of the attribute at the specified index. This
348      * method will overwrite the non-normalized value of the attribute.
349      *
350      * @param attrIndex The attribute index.
351      * @param attrValue The new attribute value.
352      *
353      * @see #setNonNormalizedValue
354      */

355     public void setValue(int attrIndex, String JavaDoc attrValue) {
356         Attribute attribute = fAttributes[attrIndex];
357         attribute.value = attrValue;
358         attribute.nonNormalizedValue = attrValue;
359     } // setValue(int,String)
360

361     /**
362      * Sets the non-normalized value of the attribute at the specified
363      * index.
364      *
365      * @param attrIndex The attribute index.
366      * @param attrValue The new non-normalized attribute value.
367      */

368     public void setNonNormalizedValue(int attrIndex, String JavaDoc attrValue) {
369         if (attrValue == null) {
370             attrValue = fAttributes[attrIndex].value;
371         }
372         fAttributes[attrIndex].nonNormalizedValue = attrValue;
373     } // setNonNormalizedValue(int,String)
374

375     /**
376      * Returns the non-normalized value of the attribute at the specified
377      * index. If no non-normalized value is set, this method will return
378      * the same value as the <code>getValue(int)</code> method.
379      *
380      * @param attrIndex The attribute index.
381      */

382     public String JavaDoc getNonNormalizedValue(int attrIndex) {
383         String JavaDoc value = fAttributes[attrIndex].nonNormalizedValue;
384         return value;
385     } // getNonNormalizedValue(int):String
386

387     /**
388      * Sets whether an attribute is specified in the instance document
389      * or not.
390      *
391      * @param attrIndex The attribute index.
392      * @param specified True if the attribute is specified in the instance
393      * document.
394      */

395     public void setSpecified(int attrIndex, boolean specified) {
396         fAttributes[attrIndex].specified = specified;
397     } // setSpecified(int,boolean)
398

399     /**
400      * Returns true if the attribute is specified in the instance document.
401      *
402      * @param attrIndex The attribute index.
403      */

404     public boolean isSpecified(int attrIndex) {
405         return fAttributes[attrIndex].specified;
406     } // isSpecified(int):boolean
407

408     //
409
// AttributeList and Attributes methods
410
//
411

412     /**
413      * Return the number of attributes in the list.
414      *
415      * <p>Once you know the number of attributes, you can iterate
416      * through the list.</p>
417      *
418      * @return The number of attributes in the list.
419      */

420     public int getLength() {
421         return fLength;
422     } // getLength():int
423

424     /**
425      * Look up an attribute's type by index.
426      *
427      * <p>The attribute type is one of the strings "CDATA", "ID",
428      * "IDREF", "IDREFS", "NMTOKEN", "NMTOKENS", "ENTITY", "ENTITIES",
429      * or "NOTATION" (always in upper case).</p>
430      *
431      * <p>If the parser has not read a declaration for the attribute,
432      * or if the parser does not report attribute types, then it must
433      * return the value "CDATA" as stated in the XML 1.0 Recommentation
434      * (clause 3.3.3, "Attribute-Value Normalization").</p>
435      *
436      * <p>For an enumerated attribute that is not a notation, the
437      * parser will report the type as "NMTOKEN".</p>
438      *
439      * @param index The attribute index (zero-based).
440      * @return The attribute's type as a string, or null if the
441      * index is out of range.
442      * @see #getLength
443      */

444     public String JavaDoc getType(int index) {
445         if (index < 0 || index >= fLength) {
446             return null;
447         }
448         return getReportableType(fAttributes[index].type);
449     } // getType(int):String
450

451     /**
452      * Look up an attribute's type by XML 1.0 qualified name.
453      *
454      * <p>See {@link #getType(int) getType(int)} for a description
455      * of the possible types.</p>
456      *
457      * @param qname The XML 1.0 qualified name.
458      * @return The attribute type as a string, or null if the
459      * attribute is not in the list or if qualified names
460      * are not available.
461      */

462     public String JavaDoc getType(String JavaDoc qname) {
463         int index = getIndex(qname);
464         return index != -1 ? getReportableType(fAttributes[index].type) : null;
465     } // getType(String):String
466

467     /**
468      * Look up an attribute's value by index.
469      *
470      * <p>If the attribute value is a list of tokens (IDREFS,
471      * ENTITIES, or NMTOKENS), the tokens will be concatenated
472      * into a single string with each token separated by a
473      * single space.</p>
474      *
475      * @param index The attribute index (zero-based).
476      * @return The attribute's value as a string, or null if the
477      * index is out of range.
478      * @see #getLength
479      */

480     public String JavaDoc getValue(int index) {
481         if (index < 0 || index >= fLength) {
482             return null;
483         }
484         return fAttributes[index].value;
485     } // getValue(int):String
486

487     /**
488      * Look up an attribute's value by XML 1.0 qualified name.
489      *
490      * <p>See {@link #getValue(int) getValue(int)} for a description
491      * of the possible values.</p>
492      *
493      * @param qname The XML 1.0 qualified name.
494      * @return The attribute value as a string, or null if the
495      * attribute is not in the list or if qualified names
496      * are not available.
497      */

498     public String JavaDoc getValue(String JavaDoc qname) {
499         int index = getIndex(qname);
500         return index != -1 ? fAttributes[index].value : null;
501     } // getValue(String):String
502

503     //
504
// AttributeList methods
505
//
506

507     /**
508      * Return the name of an attribute in this list (by position).
509      *
510      * <p>The names must be unique: the SAX parser shall not include the
511      * same attribute twice. Attributes without values (those declared
512      * #IMPLIED without a value specified in the start tag) will be
513      * omitted from the list.</p>
514      *
515      * <p>If the attribute name has a namespace prefix, the prefix
516      * will still be attached.</p>
517      *
518      * @param index The index of the attribute in the list (starting at 0).
519      * @return The name of the indexed attribute, or null
520      * if the index is out of range.
521      * @see #getLength
522      */

523     public String JavaDoc getName(int index) {
524         if (index < 0 || index >= fLength) {
525             return null;
526         }
527         return fAttributes[index].name.rawname;
528     } // getName(int):String
529

530     //
531
// Attributes methods
532
//
533

534     /**
535      * Look up the index of an attribute by XML 1.0 qualified name.
536      *
537      * @param qName The qualified (prefixed) name.
538      * @return The index of the attribute, or -1 if it does not
539      * appear in the list.
540      */

541     public int getIndex(String JavaDoc qName) {
542         for (int i = 0; i < fLength; i++) {
543             Attribute attribute = fAttributes[i];
544             if (attribute.name.rawname != null &&
545                 attribute.name.rawname.equals(qName)) {
546                 return i;
547             }
548         }
549         return -1;
550     } // getIndex(String):int
551

552     /**
553      * Look up the index of an attribute by Namespace name.
554      *
555      * @param uri The Namespace URI, or null if
556      * the name has no Namespace URI.
557      * @param localPart The attribute's local name.
558      * @return The index of the attribute, or -1 if it does not
559      * appear in the list.
560      */

561     public int getIndex(String JavaDoc uri, String JavaDoc localPart) {
562         for (int i = 0; i < fLength; i++) {
563             Attribute attribute = fAttributes[i];
564             if (attribute.name.localpart != null &&
565                 attribute.name.localpart.equals(localPart) &&
566                 ((uri==attribute.name.uri) ||
567                 (uri!=null && attribute.name.uri!=null && attribute.name.uri.equals(uri))))
568             {
569                 return i;
570             }
571         }
572         return -1;
573     } // getIndex(String,String):int
574

575     /**
576      * Look up an attribute's local name by index.
577      *
578      * @param index The attribute index (zero-based).
579      * @return The local name, or the empty string if Namespace
580      * processing is not being performed, or null
581      * if the index is out of range.
582      * @see #getLength
583      */

584     public String JavaDoc getLocalName(int index) {
585         if (!fNamespaces) {
586             return "";
587         }
588         if (index < 0 || index >= fLength) {
589             return null;
590         }
591         return fAttributes[index].name.localpart;
592     } // getLocalName(int):String
593

594     /**
595      * Look up an attribute's XML 1.0 qualified name by index.
596      *
597      * @param index The attribute index (zero-based).
598      * @return The XML 1.0 qualified name, or the empty string
599      * if none is available, or null if the index
600      * is out of range.
601      * @see #getLength
602      */

603     public String JavaDoc getQName(int index) {
604         if (index < 0 || index >= fLength) {
605             return null;
606         }
607         String JavaDoc rawname = fAttributes[index].name.rawname;
608         return rawname != null ? rawname : "";
609     } // getQName(int):String
610

611     /**
612      * Look up an attribute's type by Namespace name.
613      *
614      * <p>See {@link #getType(int) getType(int)} for a description
615      * of the possible types.</p>
616      *
617      * @param uri The Namespace URI, or null if the
618      * name has no Namespace URI.
619      * @param localName The local name of the attribute.
620      * @return The attribute type as a string, or null if the
621      * attribute is not in the list or if Namespace
622      * processing is not being performed.
623      */

624     public String JavaDoc getType(String JavaDoc uri, String JavaDoc localName) {
625         if (!fNamespaces) {
626             return null;
627         }
628         int index = getIndex(uri, localName);
629         return index != -1 ? getReportableType(fAttributes[index].type) : null;
630     } // getType(String,String):String
631

632     /**
633      * Returns the prefix of the attribute at the specified index.
634      *
635      * @param index The index of the attribute.
636      */

637     public String JavaDoc getPrefix(int index) {
638         if (index < 0 || index >= fLength) {
639             return null;
640         }
641         String JavaDoc prefix = fAttributes[index].name.prefix;
642         // REVISIT: The empty string is not entered in the symbol table!
643
return prefix != null ? prefix : "";
644     } // getPrefix(int):String
645

646     /**
647      * Look up an attribute's Namespace URI by index.
648      *
649      * @param index The attribute index (zero-based).
650      * @return The Namespace URI
651      * @see #getLength
652      */

653     public String JavaDoc getURI(int index) {
654         if (index < 0 || index >= fLength) {
655             return null;
656         }
657         String JavaDoc uri = fAttributes[index].name.uri;
658         return uri;
659     } // getURI(int):String
660

661     /**
662      * Look up an attribute's value by Namespace name.
663      *
664      * <p>See {@link #getValue(int) getValue(int)} for a description
665      * of the possible values.</p>
666      *
667      * @param uri The Namespace URI, or null if the
668      * @param localName The local name of the attribute.
669      * @return The attribute value as a string, or null if the
670      * attribute is not in the list.
671      */

672     public String JavaDoc getValue(String JavaDoc uri, String JavaDoc localName) {
673         int index = getIndex(uri, localName);
674         return index != -1 ? getValue(index) : null;
675     } // getValue(String,String):String
676

677
678     /**
679      * Look up an augmentations by Namespace name.
680      *
681      * @param uri The Namespace URI, or null if the
682      * @param localName The local name of the attribute.
683      * @return Augmentations
684      */

685     public Augmentations getAugmentations (String JavaDoc uri, String JavaDoc localName) {
686         int index = getIndex(uri, localName);
687         return index != -1 ? fAttributes[index].augs : null;
688     }
689
690     /**
691      * Look up an augmentation by XML 1.0 qualified name.
692      * <p>
693      *
694      * @param qName The XML 1.0 qualified name.
695      *
696      * @return Augmentations
697      *
698      */

699     public Augmentations getAugmentations(String JavaDoc qName){
700         int index = getIndex(qName);
701         return index != -1 ? fAttributes[index].augs : null;
702     }
703
704     /**
705      * Look up an augmentations by attributes index.
706      *
707      * @param attributeIndex The attribute index.
708      * @return Augmentations
709      */

710     public Augmentations getAugmentations (int attributeIndex){
711         if (attributeIndex < 0 || attributeIndex >= fLength) {
712             return null;
713         }
714         return fAttributes[attributeIndex].augs;
715     }
716
717     /**
718      * Sets the augmentations of the attribute at the specified index.
719      *
720      * @param attrIndex The attribute index.
721      * @param augs The augmentations.
722      */

723     public void setAugmentations(int attrIndex, Augmentations augs) {
724         fAttributes[attrIndex].augs = augs;
725     }
726
727     /**
728      * Sets the uri of the attribute at the specified index.
729      *
730      * @param attrIndex The attribute index.
731      * @param uri Namespace uri
732      */

733     public void setURI(int attrIndex, String JavaDoc uri) {
734         fAttributes[attrIndex].name.uri = uri;
735     } // getURI(int,QName)
736

737     // Implementation methods
738
public void setSchemaId(int attrIndex, boolean schemaId) {
739         fAttributes[attrIndex].schemaId = schemaId;
740     }
741     public boolean getSchemaId(int index) {
742         if (index < 0 || index >= fLength) {
743             return false;
744         }
745         return fAttributes[index].schemaId;
746     }
747     public boolean getSchemaId(String JavaDoc qname) {
748         int index = getIndex(qname);
749         return index != -1 ? fAttributes[index].schemaId : false;
750     } // getType(String):String
751
public boolean getSchemaId(String JavaDoc uri, String JavaDoc localName) {
752         if (!fNamespaces) {
753             return false;
754         }
755         int index = getIndex(uri, localName);
756         return index != -1 ? fAttributes[index].schemaId : false;
757     } // getType(String,String):String
758

759     /**
760      * Look up the index of an attribute by XML 1.0 qualified name.
761      * <p>
762      * <strong>Note:</strong>
763      * This method uses reference comparison, and thus should
764      * only be used internally. We cannot use this method in any
765      * code exposed to users as they may not pass in unique strings.
766      *
767      * @param qName The qualified (prefixed) name.
768      * @return The index of the attribute, or -1 if it does not
769      * appear in the list.
770      */

771     public int getIndexFast(String JavaDoc qName) {
772         for (int i = 0; i < fLength; ++i) {
773             Attribute attribute = fAttributes[i];
774             if (attribute.name.rawname == qName) {
775                 return i;
776             }
777         }
778         return -1;
779     } // getIndexFast(String):int
780

781     /**
782      * Adds an attribute. The attribute's non-normalized value of the
783      * attribute will have the same value as the attribute value until
784      * set using the <code>setNonNormalizedValue</code> method. Also,
785      * the added attribute will be marked as specified in the XML instance
786      * document unless set otherwise using the <code>setSpecified</code>
787      * method.
788      * <p>
789      * This method differs from <code>addAttribute</code> in that it
790      * does not check if an attribute of the same name already exists
791      * in the list before adding it. In order to improve performance
792      * of namespace processing, this method allows uniqueness checks
793      * to be deferred until all the namespace information is available
794      * after the entire attribute specification has been read.
795      * <p>
796      * <strong>Caution:</strong> If this method is called it should
797      * not be mixed with calls to <code>addAttribute</code> unless
798      * it has been determined that all the attribute names are unique.
799      *
800      * @param name the attribute name
801      * @param type the attribute type
802      * @param value the attribute value
803      *
804      * @see #setNonNormalizedValue
805      * @see #setSpecified
806      * @see #checkDuplicatesNS
807      */

808     public void addAttributeNS(QName name, String JavaDoc type, String JavaDoc value) {
809         int index = fLength;
810         if (fLength++ == fAttributes.length) {
811             Attribute[] attributes;
812             if (fLength < SIZE_LIMIT) {
813                 attributes = new Attribute[fAttributes.length + 4];
814             }
815             else {
816                 attributes = new Attribute[fAttributes.length << 1];
817             }
818             System.arraycopy(fAttributes, 0, attributes, 0, fAttributes.length);
819             for (int i = fAttributes.length; i < attributes.length; i++) {
820                 attributes[i] = new Attribute();
821             }
822             fAttributes = attributes;
823         }
824         
825         // set values
826
Attribute attribute = fAttributes[index];
827         attribute.name.setValues(name);
828         attribute.type = type;
829         attribute.value = value;
830         attribute.nonNormalizedValue = value;
831         attribute.specified = false;
832             
833         // clear augmentations
834
attribute.augs.removeAllItems();
835     }
836     
837     /**
838      * Checks for duplicate expanded names (local part and namespace name
839      * pairs) in the attribute specification. If a duplicate is found its
840      * name is returned.
841      * <p>
842      * This should be called once all the in-scope namespaces for the element
843      * enclosing these attributes is known, and after all the attributes
844      * have gone through namespace binding.
845      *
846      * @return the name of a duplicate attribute found in the search,
847      * otherwise null.
848      */

849     public QName checkDuplicatesNS() {
850         // If the list is small check for duplicates using pairwise comparison.
851
if (fLength <= SIZE_LIMIT) {
852             for (int i = 0; i < fLength - 1; ++i) {
853                 Attribute att1 = fAttributes[i];
854                 for (int j = i + 1; j < fLength; ++j) {
855                     Attribute att2 = fAttributes[j];
856                     if (att1.name.localpart == att2.name.localpart &&
857                         att1.name.uri == att2.name.uri) {
858                         return att2.name;
859                     }
860                 }
861             }
862         }
863         // If the list is large check duplicates using a hash table.
864
else {
865             // We don't want this table view to be read if someone calls
866
// addAttribute so we invalidate it up front.
867
fIsTableViewConsistent = false;
868
869             prepareTableView();
870
871             Attribute attr;
872             int bucket;
873
874             for (int i = fLength - 1; i >= 0; --i) {
875                 attr = fAttributes[i];
876                 bucket = getTableViewBucket(attr.name.localpart, attr.name.uri);
877                 
878                 // The chain is stale.
879
// This must be a unique attribute.
880
if (fAttributeTableViewChainState[bucket] != fLargeCount) {
881                     fAttributeTableViewChainState[bucket] = fLargeCount;
882                     attr.next = null;
883                     fAttributeTableView[bucket] = attr;
884                 }
885                 // This chain is active.
886
// We need to check if any of the attributes has the same name.
887
else {
888                     // Search the table.
889
Attribute found = fAttributeTableView[bucket];
890                     while (found != null) {
891                         if (found.name.localpart == attr.name.localpart &&
892                             found.name.uri == attr.name.uri) {
893                             return attr.name;
894                         }
895                         found = found.next;
896                     }
897                     
898                     // Update table view
899
attr.next = fAttributeTableView[bucket];
900                     fAttributeTableView[bucket] = attr;
901                 }
902             }
903         }
904         return null;
905     }
906     
907     /**
908      * Look up the index of an attribute by Namespace name.
909      * <p>
910      * <strong>Note:</strong>
911      * This method uses reference comparison, and thus should
912      * only be used internally. We cannot use this method in any
913      * code exposed to users as they may not pass in unique strings.
914      *
915      * @param uri The Namespace URI, or null if
916      * the name has no Namespace URI.
917      * @param localPart The attribute's local name.
918      * @return The index of the attribute, or -1 if it does not
919      * appear in the list.
920      */

921     public int getIndexFast(String JavaDoc uri, String JavaDoc localPart) {
922         for (int i = 0; i < fLength; ++i) {
923             Attribute attribute = fAttributes[i];
924             if (attribute.name.localpart == localPart &&
925                 attribute.name.uri == uri) {
926                 return i;
927             }
928         }
929         return -1;
930     } // getIndexFast(String,String):int
931

932     /**
933      * Returns the value passed in or NMTOKEN if it's an enumerated type.
934      *
935      * @param type attribute type
936      * @return the value passed in or NMTOKEN if it's an enumerated type.
937      */

938     private String JavaDoc getReportableType(String JavaDoc type) {
939
940         if (type.charAt(0) == '(') {
941             return "NMTOKEN";
942         }
943         return type;
944     }
945     
946     /**
947      * Returns the position in the table view
948      * where the given attribute name would be hashed.
949      *
950      * @param qname the attribute name
951      * @return the position in the table view where the given attribute
952      * would be hashed
953      */

954     protected int getTableViewBucket(String JavaDoc qname) {
955         return (qname.hashCode() & 0x7FFFFFFF) % fTableViewBuckets;
956     }
957     
958     /**
959      * Returns the position in the table view
960      * where the given attribute name would be hashed.
961      *
962      * @param localpart the local part of the attribute
963      * @param uri the namespace name of the attribute
964      * @return the position in the table view where the given attribute
965      * would be hashed
966      */

967     protected int getTableViewBucket(String JavaDoc localpart, String JavaDoc uri) {
968         if (uri == null) {
969             return (localpart.hashCode() & 0x7FFFFFFF) % fTableViewBuckets;
970         }
971         else {
972             return ((localpart.hashCode() + uri.hashCode())
973                & 0x7FFFFFFF) % fTableViewBuckets;
974         }
975     }
976     
977     /**
978      * Purges all elements from the table view.
979      */

980     protected void cleanTableView() {
981         if (++fLargeCount < 0) {
982             // Overflow. We actually need to visit the chain state array.
983
if (fAttributeTableViewChainState != null) {
984                 for (int i = fTableViewBuckets - 1; i >= 0; --i) {
985                     fAttributeTableViewChainState[i] = 0;
986                 }
987             }
988             fLargeCount = 1;
989         }
990     }
991     
992     /**
993      * Prepares the table view of the attributes list for use.
994      */

995     protected void prepareTableView() {
996         if (fAttributeTableView == null) {
997             fAttributeTableView = new Attribute[fTableViewBuckets];
998             fAttributeTableViewChainState = new int[fTableViewBuckets];
999         }
1000        else {
1001            cleanTableView();
1002        }
1003    }
1004    
1005    /**
1006     * Prepares the table view of the attributes list for use,
1007     * and populates it with the attributes which have been
1008     * previously read.
1009     */

1010    protected void prepareAndPopulateTableView() {
1011        prepareTableView();
1012        // Need to populate the hash table with the attributes we've scanned so far.
1013
Attribute attr;
1014        int bucket;
1015        for (int i = 0; i < fLength; ++i) {
1016            attr = fAttributes[i];
1017            bucket = getTableViewBucket(attr.name.rawname);
1018            if (fAttributeTableViewChainState[bucket] != fLargeCount) {
1019                fAttributeTableViewChainState[bucket] = fLargeCount;
1020                attr.next = null;
1021                fAttributeTableView[bucket] = attr;
1022            }
1023            else {
1024                // Update table view
1025
attr.next = fAttributeTableView[bucket];
1026                fAttributeTableView[bucket] = attr;
1027            }
1028        }
1029    }
1030
1031    //
1032
// Classes
1033
//
1034

1035    /**
1036     * Attribute information.
1037     *
1038     * @author Andy Clark, IBM
1039     */

1040    static class Attribute {
1041        
1042        //
1043
// Data
1044
//
1045

1046        // basic info
1047

1048        /** Name. */
1049        public QName name = new QName();
1050
1051        /** Type. */
1052        public String JavaDoc type;
1053
1054        /** Value. */
1055        public String JavaDoc value;
1056
1057        /** Non-normalized value. */
1058        public String JavaDoc nonNormalizedValue;
1059
1060        /** Specified. */
1061        public boolean specified;
1062
1063        /** Schema ID type. */
1064        public boolean schemaId;
1065        
1066        /**
1067         * Augmentations information for this attribute.
1068         * XMLAttributes has no knowledge if any augmentations
1069         * were attached to Augmentations.
1070         */

1071        public Augmentations augs = new AugmentationsImpl();
1072        
1073        // Additional data for attribute table view
1074

1075        /** Pointer to the next attribute in the chain. **/
1076        public Attribute next;
1077        
1078    } // class Attribute
1079

1080} // class XMLAttributesImpl
1081
Popular Tags