2
* Licensed to the Apache Software Foundation (ASF) under one or more
3
* contributor license agreements. See the NOTICE file distributed with
4
* this work for additional information regarding copyright ownership.
5
* The ASF licenses this file to You under the Apache License, Version 2.0
6
* (the "License"); you may not use this file except in compliance with
7
* the License. You may obtain a copy of the License at
9
* http://www.apache.org/licenses/LICENSE-2.0
11
* Unless required by applicable law or agreed to in writing, software
12
* distributed under the License is distributed on an "AS IS" BASIS,
13
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
* See the License for the specific language governing permissions and
15
* limitations under the License.
18
package org.apache.xerces.util;
20
import org.apache.xerces.xni.Augmentations;
21
import org.apache.xerces.xni.QName;
22
import org.apache.xerces.xni.XMLAttributes;
25
* The XMLAttributesImpl class is an implementation of the XMLAttributes
26
* interface which defines a collection of attributes for an element.
27
* In the parser, the document source would scan the entire start element
28
* and collect the attributes. The attributes are communicated to the
29
* document handler in the startElement method.
31
* The attributes are read-write so that subsequent stages in the document
32
* pipeline can modify the values or change the attributes that are
33
* propogated to the next stage.
35
* @see org.apache.xerces.xni.XMLDocumentHandler#startElement
37
* @author Andy Clark, IBM
38
* @author Elena Litani, IBM
39
* @author Michael Glavassevich, IBM
41
* @version $Id: XMLAttributesImpl.java,v 1.2 2009/12/10 03:18:07 matthewoliver Exp $
43
public class XMLAttributesImpl
44
implements XMLAttributes {
50
/** Default table size. */
51
protected static final int TABLE_SIZE = 101;
54
* Threshold at which an instance is treated
55
* as a large attribute list.
57
protected static final int SIZE_LIMIT = 20;
66
protected boolean fNamespaces = true;
71
* Usage count for the attribute table view.
72
* Incremented each time all attributes are removed
73
* when the attribute table view is in use.
75
protected int fLargeCount = 1;
77
/** Attribute count. */
78
protected int fLength;
80
/** Attribute information. */
81
protected Attribute[] fAttributes = new Attribute[4];
84
* Hashtable of attribute information.
85
* Provides an alternate view of the attribute specification.
87
protected Attribute[] fAttributeTableView;
90
* Tracks whether each chain in the hash table is stale
91
* with respect to the current state of this object.
92
* A chain is stale if its state is not the same as the number
93
* of times the attribute table view has been used.
95
protected int[] fAttributeTableViewChainState;
98
* Actual number of buckets in the table view.
100
protected int fTableViewBuckets;
103
* Indicates whether the table view contains consistent data.
105
protected boolean fIsTableViewConsistent;
111
/** Default constructor. */
112
public XMLAttributesImpl() {
117
* @param tableSize initial size of table view
119
public XMLAttributesImpl(int tableSize) {
120
fTableViewBuckets = tableSize;
121
for (int i = 0; i < fAttributes.length; i++) {
122
fAttributes[i] = new Attribute();
131
* Sets whether namespace processing is being performed. This state
132
* is needed to return the correct value from the getLocalName method.
134
* @param namespaces True if namespace processing is turned on.
138
public void setNamespaces(boolean namespaces) {
139
fNamespaces = namespaces;
140
} // setNamespaces(boolean)
143
// XMLAttributes methods
147
* Adds an attribute. The attribute's non-normalized value of the
148
* attribute will have the same value as the attribute value until
149
* set using the <code>setNonNormalizedValue</code> method. Also,
150
* the added attribute will be marked as specified in the XML instance
151
* document unless set otherwise using the <code>setSpecified</code>
154
* <strong>Note:</strong> If an attribute of the same name already
155
* exists, the old values for the attribute are replaced by the new
158
* @param name The attribute name.
159
* @param type The attribute type. The type name is determined by
160
* the type specified for this attribute in the DTD.
161
* For example: "CDATA", "ID", "NMTOKEN", etc. However,
162
* attributes of type enumeration will have the type
163
* value specified as the pipe ('|') separated list of
164
* the enumeration values prefixed by an open
165
* parenthesis and suffixed by a close parenthesis.
166
* For example: "(true|false)".
167
* @param value The attribute value.
169
* @return Returns the attribute index.
171
* @see #setNonNormalizedValue
174
public int addAttribute(QName name, String type, String value) {
177
if (fLength < SIZE_LIMIT) {
178
index = name.uri != null && !name.uri.equals("")
179
? getIndexFast(name.uri, name.localpart)
180
: getIndexFast(name.rawname);
184
if (fLength++ == fAttributes.length) {
185
Attribute[] attributes = new Attribute[fAttributes.length + 4];
186
System.arraycopy(fAttributes, 0, attributes, 0, fAttributes.length);
187
for (int i = fAttributes.length; i < attributes.length; i++) {
188
attributes[i] = new Attribute();
190
fAttributes = attributes;
194
else if (name.uri == null ||
195
name.uri.length() == 0 ||
196
(index = getIndexFast(name.uri, name.localpart)) == -1) {
199
* If attributes were removed from the list after the table
200
* becomes in use this isn't reflected in the table view. It's
201
* assumed that once a user starts removing attributes they're
202
* not likely to add more. We only make the view consistent if
203
* the user of this class adds attributes, removes them, and
206
if (!fIsTableViewConsistent || fLength == SIZE_LIMIT) {
207
prepareAndPopulateTableView();
208
fIsTableViewConsistent = true;
211
int bucket = getTableViewBucket(name.rawname);
213
// The chain is stale.
214
// This must be a unique attribute.
215
if (fAttributeTableViewChainState[bucket] != fLargeCount) {
217
if (fLength++ == fAttributes.length) {
218
Attribute[] attributes = new Attribute[fAttributes.length << 1];
219
System.arraycopy(fAttributes, 0, attributes, 0, fAttributes.length);
220
for (int i = fAttributes.length; i < attributes.length; i++) {
221
attributes[i] = new Attribute();
223
fAttributes = attributes;
226
// Update table view.
227
fAttributeTableViewChainState[bucket] = fLargeCount;
228
fAttributes[index].next = null;
229
fAttributeTableView[bucket] = fAttributes[index];
231
// This chain is active.
232
// We need to check if any of the attributes has the same rawname.
235
Attribute found = fAttributeTableView[bucket];
236
while (found != null) {
237
if (found.name.rawname == name.rawname) {
242
// This attribute is unique.
245
if (fLength++ == fAttributes.length) {
246
Attribute[] attributes = new Attribute[fAttributes.length << 1];
247
System.arraycopy(fAttributes, 0, attributes, 0, fAttributes.length);
248
for (int i = fAttributes.length; i < attributes.length; i++) {
249
attributes[i] = new Attribute();
251
fAttributes = attributes;
255
fAttributes[index].next = fAttributeTableView[bucket];
256
fAttributeTableView[bucket] = fAttributes[index];
258
// Duplicate. We still need to find the index.
260
index = getIndexFast(name.rawname);
266
Attribute attribute = fAttributes[index];
267
attribute.name.setValues(name);
268
attribute.type = type;
269
attribute.value = value;
270
attribute.nonNormalizedValue = value;
271
attribute.specified = false;
273
// clear augmentations
274
attribute.augs.removeAllItems();
278
} // addAttribute(QName,String,XMLString)
281
* Removes all of the attributes. This method will also remove all
282
* entities associated to the attributes.
284
public void removeAllAttributes() {
286
} // removeAllAttributes()
289
* Removes the attribute at the specified index.
291
* <strong>Note:</strong> This operation changes the indexes of all
292
* attributes following the attribute at the specified index.
294
* @param attrIndex The attribute index.
296
public void removeAttributeAt(int attrIndex) {
297
fIsTableViewConsistent = false;
298
if (attrIndex < fLength - 1) {
299
Attribute removedAttr = fAttributes[attrIndex];
300
System.arraycopy(fAttributes, attrIndex + 1,
301
fAttributes, attrIndex, fLength - attrIndex - 1);
302
// Make the discarded Attribute object available for re-use
303
// by tucking it after the Attributes that are still in use
304
fAttributes[fLength-1] = removedAttr;
307
} // removeAttributeAt(int)
310
* Sets the name of the attribute at the specified index.
312
* @param attrIndex The attribute index.
313
* @param attrName The new attribute name.
315
public void setName(int attrIndex, QName attrName) {
316
fAttributes[attrIndex].name.setValues(attrName);
317
} // setName(int,QName)
320
* Sets the fields in the given QName structure with the values
321
* of the attribute name at the specified index.
323
* @param attrIndex The attribute index.
324
* @param attrName The attribute name structure to fill in.
326
public void getName(int attrIndex, QName attrName) {
327
attrName.setValues(fAttributes[attrIndex].name);
328
} // getName(int,QName)
331
* Sets the type of the attribute at the specified index.
333
* @param attrIndex The attribute index.
334
* @param attrType The attribute type. The type name is determined by
335
* the type specified for this attribute in the DTD.
336
* For example: "CDATA", "ID", "NMTOKEN", etc. However,
337
* attributes of type enumeration will have the type
338
* value specified as the pipe ('|') separated list of
339
* the enumeration values prefixed by an open
340
* parenthesis and suffixed by a close parenthesis.
341
* For example: "(true|false)".
343
public void setType(int attrIndex, String attrType) {
344
fAttributes[attrIndex].type = attrType;
345
} // setType(int,String)
348
* Sets the value of the attribute at the specified index. This
349
* method will overwrite the non-normalized value of the attribute.
351
* @param attrIndex The attribute index.
352
* @param attrValue The new attribute value.
354
* @see #setNonNormalizedValue
356
public void setValue(int attrIndex, String attrValue) {
357
Attribute attribute = fAttributes[attrIndex];
358
attribute.value = attrValue;
359
attribute.nonNormalizedValue = attrValue;
360
} // setValue(int,String)
363
* Sets the non-normalized value of the attribute at the specified
366
* @param attrIndex The attribute index.
367
* @param attrValue The new non-normalized attribute value.
369
public void setNonNormalizedValue(int attrIndex, String attrValue) {
370
if (attrValue == null) {
371
attrValue = fAttributes[attrIndex].value;
373
fAttributes[attrIndex].nonNormalizedValue = attrValue;
374
} // setNonNormalizedValue(int,String)
377
* Returns the non-normalized value of the attribute at the specified
378
* index. If no non-normalized value is set, this method will return
379
* the same value as the <code>getValue(int)</code> method.
381
* @param attrIndex The attribute index.
383
public String getNonNormalizedValue(int attrIndex) {
384
String value = fAttributes[attrIndex].nonNormalizedValue;
386
} // getNonNormalizedValue(int):String
389
* Sets whether an attribute is specified in the instance document
392
* @param attrIndex The attribute index.
393
* @param specified True if the attribute is specified in the instance
396
public void setSpecified(int attrIndex, boolean specified) {
397
fAttributes[attrIndex].specified = specified;
398
} // setSpecified(int,boolean)
401
* Returns true if the attribute is specified in the instance document.
403
* @param attrIndex The attribute index.
405
public boolean isSpecified(int attrIndex) {
406
return fAttributes[attrIndex].specified;
407
} // isSpecified(int):boolean
410
// AttributeList and Attributes methods
414
* Return the number of attributes in the list.
416
* <p>Once you know the number of attributes, you can iterate
417
* through the list.</p>
419
* @return The number of attributes in the list.
421
public int getLength() {
426
* Look up an attribute's type by index.
428
* <p>The attribute type is one of the strings "CDATA", "ID",
429
* "IDREF", "IDREFS", "NMTOKEN", "NMTOKENS", "ENTITY", "ENTITIES",
430
* or "NOTATION" (always in upper case).</p>
432
* <p>If the parser has not read a declaration for the attribute,
433
* or if the parser does not report attribute types, then it must
434
* return the value "CDATA" as stated in the XML 1.0 Recommentation
435
* (clause 3.3.3, "Attribute-Value Normalization").</p>
437
* <p>For an enumerated attribute that is not a notation, the
438
* parser will report the type as "NMTOKEN".</p>
440
* @param index The attribute index (zero-based).
441
* @return The attribute's type as a string, or null if the
442
* index is out of range.
445
public String getType(int index) {
446
if (index < 0 || index >= fLength) {
449
return getReportableType(fAttributes[index].type);
450
} // getType(int):String
453
* Look up an attribute's type by XML 1.0 qualified name.
455
* <p>See {@link #getType(int) getType(int)} for a description
456
* of the possible types.</p>
458
* @param qname The XML 1.0 qualified name.
459
* @return The attribute type as a string, or null if the
460
* attribute is not in the list or if qualified names
463
public String getType(String qname) {
464
int index = getIndex(qname);
465
return index != -1 ? getReportableType(fAttributes[index].type) : null;
466
} // getType(String):String
469
* Look up an attribute's value by index.
471
* <p>If the attribute value is a list of tokens (IDREFS,
472
* ENTITIES, or NMTOKENS), the tokens will be concatenated
473
* into a single string with each token separated by a
476
* @param index The attribute index (zero-based).
477
* @return The attribute's value as a string, or null if the
478
* index is out of range.
481
public String getValue(int index) {
482
if (index < 0 || index >= fLength) {
485
return fAttributes[index].value;
486
} // getValue(int):String
489
* Look up an attribute's value by XML 1.0 qualified name.
491
* <p>See {@link #getValue(int) getValue(int)} for a description
492
* of the possible values.</p>
494
* @param qname The XML 1.0 qualified name.
495
* @return The attribute value as a string, or null if the
496
* attribute is not in the list or if qualified names
499
public String getValue(String qname) {
500
int index = getIndex(qname);
501
return index != -1 ? fAttributes[index].value : null;
502
} // getValue(String):String
505
// AttributeList methods
509
* Return the name of an attribute in this list (by position).
511
* <p>The names must be unique: the SAX parser shall not include the
512
* same attribute twice. Attributes without values (those declared
513
* #IMPLIED without a value specified in the start tag) will be
514
* omitted from the list.</p>
516
* <p>If the attribute name has a namespace prefix, the prefix
517
* will still be attached.</p>
519
* @param index The index of the attribute in the list (starting at 0).
520
* @return The name of the indexed attribute, or null
521
* if the index is out of range.
524
public String getName(int index) {
525
if (index < 0 || index >= fLength) {
528
return fAttributes[index].name.rawname;
529
} // getName(int):String
532
// Attributes methods
536
* Look up the index of an attribute by XML 1.0 qualified name.
538
* @param qName The qualified (prefixed) name.
539
* @return The index of the attribute, or -1 if it does not
540
* appear in the list.
542
public int getIndex(String qName) {
543
for (int i = 0; i < fLength; i++) {
544
Attribute attribute = fAttributes[i];
545
if (attribute.name.rawname != null &&
546
attribute.name.rawname.equals(qName)) {
551
} // getIndex(String):int
554
* Look up the index of an attribute by Namespace name.
556
* @param uri The Namespace URI, or null if
557
* the name has no Namespace URI.
558
* @param localPart The attribute's local name.
559
* @return The index of the attribute, or -1 if it does not
560
* appear in the list.
562
public int getIndex(String uri, String localPart) {
563
for (int i = 0; i < fLength; i++) {
564
Attribute attribute = fAttributes[i];
565
if (attribute.name.localpart != null &&
566
attribute.name.localpart.equals(localPart) &&
567
((uri==attribute.name.uri) ||
568
(uri!=null && attribute.name.uri!=null && attribute.name.uri.equals(uri))))
574
} // getIndex(String,String):int
577
* Look up an attribute's local name by index.
579
* @param index The attribute index (zero-based).
580
* @return The local name, or the empty string if Namespace
581
* processing is not being performed, or null
582
* if the index is out of range.
585
public String getLocalName(int index) {
589
if (index < 0 || index >= fLength) {
592
return fAttributes[index].name.localpart;
593
} // getLocalName(int):String
596
* Look up an attribute's XML 1.0 qualified name by index.
598
* @param index The attribute index (zero-based).
599
* @return The XML 1.0 qualified name, or the empty string
600
* if none is available, or null if the index
604
public String getQName(int index) {
605
if (index < 0 || index >= fLength) {
608
String rawname = fAttributes[index].name.rawname;
609
return rawname != null ? rawname : "";
610
} // getQName(int):String
613
* Look up an attribute's type by Namespace name.
615
* <p>See {@link #getType(int) getType(int)} for a description
616
* of the possible types.</p>
618
* @param uri The Namespace URI, or null if the
619
* name has no Namespace URI.
620
* @param localName The local name of the attribute.
621
* @return The attribute type as a string, or null if the
622
* attribute is not in the list or if Namespace
623
* processing is not being performed.
625
public String getType(String uri, String localName) {
629
int index = getIndex(uri, localName);
630
return index != -1 ? getReportableType(fAttributes[index].type) : null;
631
} // getType(String,String):String
634
* Returns the prefix of the attribute at the specified index.
636
* @param index The index of the attribute.
638
public String getPrefix(int index) {
639
if (index < 0 || index >= fLength) {
642
String prefix = fAttributes[index].name.prefix;
643
// REVISIT: The empty string is not entered in the symbol table!
644
return prefix != null ? prefix : "";
645
} // getPrefix(int):String
648
* Look up an attribute's Namespace URI by index.
650
* @param index The attribute index (zero-based).
651
* @return The Namespace URI
654
public String getURI(int index) {
655
if (index < 0 || index >= fLength) {
658
String uri = fAttributes[index].name.uri;
660
} // getURI(int):String
663
* Look up an attribute's value by Namespace name.
665
* <p>See {@link #getValue(int) getValue(int)} for a description
666
* of the possible values.</p>
668
* @param uri The Namespace URI, or null if the
669
* @param localName The local name of the attribute.
670
* @return The attribute value as a string, or null if the
671
* attribute is not in the list.
673
public String getValue(String uri, String localName) {
674
int index = getIndex(uri, localName);
675
return index != -1 ? getValue(index) : null;
676
} // getValue(String,String):String
680
* Look up an augmentations by Namespace name.
682
* @param uri The Namespace URI, or null if the
683
* @param localName The local name of the attribute.
684
* @return Augmentations
686
public Augmentations getAugmentations (String uri, String localName) {
687
int index = getIndex(uri, localName);
688
return index != -1 ? fAttributes[index].augs : null;
692
* Look up an augmentation by XML 1.0 qualified name.
695
* @param qName The XML 1.0 qualified name.
697
* @return Augmentations
700
public Augmentations getAugmentations(String qName){
701
int index = getIndex(qName);
702
return index != -1 ? fAttributes[index].augs : null;
706
* Look up an augmentations by attributes index.
708
* @param attributeIndex The attribute index.
709
* @return Augmentations
711
public Augmentations getAugmentations (int attributeIndex){
712
if (attributeIndex < 0 || attributeIndex >= fLength) {
715
return fAttributes[attributeIndex].augs;
719
* Sets the augmentations of the attribute at the specified index.
721
* @param attrIndex The attribute index.
722
* @param augs The augmentations.
724
public void setAugmentations(int attrIndex, Augmentations augs) {
725
fAttributes[attrIndex].augs = augs;
729
* Sets the uri of the attribute at the specified index.
731
* @param attrIndex The attribute index.
732
* @param uri Namespace uri
734
public void setURI(int attrIndex, String uri) {
735
fAttributes[attrIndex].name.uri = uri;
736
} // getURI(int,QName)
738
// Implementation methods
739
public void setSchemaId(int attrIndex, boolean schemaId) {
740
fAttributes[attrIndex].schemaId = schemaId;
742
public boolean getSchemaId(int index) {
743
if (index < 0 || index >= fLength) {
746
return fAttributes[index].schemaId;
748
public boolean getSchemaId(String qname) {
749
int index = getIndex(qname);
750
return index != -1 ? fAttributes[index].schemaId : false;
751
} // getType(String):String
752
public boolean getSchemaId(String uri, String localName) {
756
int index = getIndex(uri, localName);
757
return index != -1 ? fAttributes[index].schemaId : false;
758
} // getType(String,String):String
761
* Look up the index of an attribute by XML 1.0 qualified name.
763
* <strong>Note:</strong>
764
* This method uses reference comparison, and thus should
765
* only be used internally. We cannot use this method in any
766
* code exposed to users as they may not pass in unique strings.
768
* @param qName The qualified (prefixed) name.
769
* @return The index of the attribute, or -1 if it does not
770
* appear in the list.
772
public int getIndexFast(String qName) {
773
for (int i = 0; i < fLength; ++i) {
774
Attribute attribute = fAttributes[i];
775
if (attribute.name.rawname == qName) {
780
} // getIndexFast(String):int
783
* Adds an attribute. The attribute's non-normalized value of the
784
* attribute will have the same value as the attribute value until
785
* set using the <code>setNonNormalizedValue</code> method. Also,
786
* the added attribute will be marked as specified in the XML instance
787
* document unless set otherwise using the <code>setSpecified</code>
790
* This method differs from <code>addAttribute</code> in that it
791
* does not check if an attribute of the same name already exists
792
* in the list before adding it. In order to improve performance
793
* of namespace processing, this method allows uniqueness checks
794
* to be deferred until all the namespace information is available
795
* after the entire attribute specification has been read.
797
* <strong>Caution:</strong> If this method is called it should
798
* not be mixed with calls to <code>addAttribute</code> unless
799
* it has been determined that all the attribute names are unique.
801
* @param name the attribute name
802
* @param type the attribute type
803
* @param value the attribute value
805
* @see #setNonNormalizedValue
807
* @see #checkDuplicatesNS
809
public void addAttributeNS(QName name, String type, String value) {
811
if (fLength++ == fAttributes.length) {
812
Attribute[] attributes;
813
if (fLength < SIZE_LIMIT) {
814
attributes = new Attribute[fAttributes.length + 4];
817
attributes = new Attribute[fAttributes.length << 1];
819
System.arraycopy(fAttributes, 0, attributes, 0, fAttributes.length);
820
for (int i = fAttributes.length; i < attributes.length; i++) {
821
attributes[i] = new Attribute();
823
fAttributes = attributes;
827
Attribute attribute = fAttributes[index];
828
attribute.name.setValues(name);
829
attribute.type = type;
830
attribute.value = value;
831
attribute.nonNormalizedValue = value;
832
attribute.specified = false;
834
// clear augmentations
835
attribute.augs.removeAllItems();
839
* Checks for duplicate expanded names (local part and namespace name
840
* pairs) in the attribute specification. If a duplicate is found its
843
* This should be called once all the in-scope namespaces for the element
844
* enclosing these attributes is known, and after all the attributes
845
* have gone through namespace binding.
847
* @return the name of a duplicate attribute found in the search,
850
public QName checkDuplicatesNS() {
851
// If the list is small check for duplicates using pairwise comparison.
852
if (fLength <= SIZE_LIMIT) {
853
for (int i = 0; i < fLength - 1; ++i) {
854
Attribute att1 = fAttributes[i];
855
for (int j = i + 1; j < fLength; ++j) {
856
Attribute att2 = fAttributes[j];
857
if (att1.name.localpart == att2.name.localpart &&
858
att1.name.uri == att2.name.uri) {
864
// If the list is large check duplicates using a hash table.
866
// We don't want this table view to be read if someone calls
867
// addAttribute so we invalidate it up front.
868
fIsTableViewConsistent = false;
875
for (int i = fLength - 1; i >= 0; --i) {
876
attr = fAttributes[i];
877
bucket = getTableViewBucket(attr.name.localpart, attr.name.uri);
879
// The chain is stale.
880
// This must be a unique attribute.
881
if (fAttributeTableViewChainState[bucket] != fLargeCount) {
882
fAttributeTableViewChainState[bucket] = fLargeCount;
884
fAttributeTableView[bucket] = attr;
886
// This chain is active.
887
// We need to check if any of the attributes has the same name.
890
Attribute found = fAttributeTableView[bucket];
891
while (found != null) {
892
if (found.name.localpart == attr.name.localpart &&
893
found.name.uri == attr.name.uri) {
900
attr.next = fAttributeTableView[bucket];
901
fAttributeTableView[bucket] = attr;
909
* Look up the index of an attribute by Namespace name.
911
* <strong>Note:</strong>
912
* This method uses reference comparison, and thus should
913
* only be used internally. We cannot use this method in any
914
* code exposed to users as they may not pass in unique strings.
916
* @param uri The Namespace URI, or null if
917
* the name has no Namespace URI.
918
* @param localPart The attribute's local name.
919
* @return The index of the attribute, or -1 if it does not
920
* appear in the list.
922
public int getIndexFast(String uri, String localPart) {
923
for (int i = 0; i < fLength; ++i) {
924
Attribute attribute = fAttributes[i];
925
if (attribute.name.localpart == localPart &&
926
attribute.name.uri == uri) {
931
} // getIndexFast(String,String):int
934
* Returns the value passed in or NMTOKEN if it's an enumerated type.
936
* @param type attribute type
937
* @return the value passed in or NMTOKEN if it's an enumerated type.
939
private String getReportableType(String type) {
941
if (type.charAt(0) == '(') {
948
* Returns the position in the table view
949
* where the given attribute name would be hashed.
951
* @param qname the attribute name
952
* @return the position in the table view where the given attribute
955
protected int getTableViewBucket(String qname) {
956
return (qname.hashCode() & 0x7FFFFFFF) % fTableViewBuckets;
960
* Returns the position in the table view
961
* where the given attribute name would be hashed.
963
* @param localpart the local part of the attribute
964
* @param uri the namespace name of the attribute
965
* @return the position in the table view where the given attribute
968
protected int getTableViewBucket(String localpart, String uri) {
970
return (localpart.hashCode() & 0x7FFFFFFF) % fTableViewBuckets;
973
return ((localpart.hashCode() + uri.hashCode())
974
& 0x7FFFFFFF) % fTableViewBuckets;
979
* Purges all elements from the table view.
981
protected void cleanTableView() {
982
if (++fLargeCount < 0) {
983
// Overflow. We actually need to visit the chain state array.
984
if (fAttributeTableViewChainState != null) {
985
for (int i = fTableViewBuckets - 1; i >= 0; --i) {
986
fAttributeTableViewChainState[i] = 0;
994
* Prepares the table view of the attributes list for use.
996
protected void prepareTableView() {
997
if (fAttributeTableView == null) {
998
fAttributeTableView = new Attribute[fTableViewBuckets];
999
fAttributeTableViewChainState = new int[fTableViewBuckets];
1007
* Prepares the table view of the attributes list for use,
1008
* and populates it with the attributes which have been
1011
protected void prepareAndPopulateTableView() {
1013
// Need to populate the hash table with the attributes we've scanned so far.
1016
for (int i = 0; i < fLength; ++i) {
1017
attr = fAttributes[i];
1018
bucket = getTableViewBucket(attr.name.rawname);
1019
if (fAttributeTableViewChainState[bucket] != fLargeCount) {
1020
fAttributeTableViewChainState[bucket] = fLargeCount;
1022
fAttributeTableView[bucket] = attr;
1025
// Update table view
1026
attr.next = fAttributeTableView[bucket];
1027
fAttributeTableView[bucket] = attr;
1037
* Attribute information.
1039
* @author Andy Clark, IBM
1041
static class Attribute {
1050
public QName name = new QName();
1056
public String value;
1058
/** Non-normalized value. */
1059
public String nonNormalizedValue;
1062
public boolean specified;
1064
/** Schema ID type. */
1065
public boolean schemaId;
1068
* Augmentations information for this attribute.
1069
* XMLAttributes has no knowledge if any augmentations
1070
* were attached to Augmentations.
1072
public Augmentations augs = new AugmentationsImpl();
1074
// Additional data for attribute table view
1076
/** Pointer to the next attribute in the chain. **/
1077
public Attribute next;
1079
} // class Attribute
1081
} // class XMLAttributesImpl