1 // AttributesImpl.java - default implementation of Attributes.
2 // http://www.saxproject.org
3 // Written by David Megginson
4 // NO WARRANTY! This class is in the public domain.
5 // $Id: AttributesImpl.java,v 1.9 2002/01/30 20:52:24 dbrownell Exp $
7 package org.xml.sax.helpers;
9 import org.xml.sax.Attributes;
13 * Default implementation of the Attributes interface.
16 * <em>This module, both source code and documentation, is in the
17 * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
18 * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
19 * for further information.
22 * <p>This class provides a default implementation of the SAX2
23 * {@link org.xml.sax.Attributes Attributes} interface, with the
24 * addition of manipulators so that the list can be modified or
27 * <p>There are two typical uses of this class:</p>
30 * <li>to take a persistent snapshot of an Attributes object
31 * in a {@link org.xml.sax.ContentHandler#startElement startElement} event; or</li>
32 * <li>to construct or modify an Attributes object in a SAX2 driver or filter.</li>
35 * <p>This class replaces the now-deprecated SAX1 {@link
36 * org.xml.sax.helpers.AttributeListImpl AttributeListImpl}
37 * class; in addition to supporting the updated Attributes
38 * interface rather than the deprecated {@link org.xml.sax.AttributeList
39 * AttributeList} interface, it also includes a much more efficient
40 * implementation using a single array rather than a set of Vectors.</p>
43 * @author David Megginson
44 * @version 2.0.1 (sax2r2)
46 public class AttributesImpl implements Attributes
50 ////////////////////////////////////////////////////////////////////
52 ////////////////////////////////////////////////////////////////////
56 * Construct a new, empty AttributesImpl object.
58 public AttributesImpl ()
66 * Copy an existing Attributes object.
68 * <p>This constructor is especially useful inside a
69 * {@link org.xml.sax.ContentHandler#startElement startElement} event.</p>
71 * @param atts The existing Attributes object.
73 public AttributesImpl (Attributes atts)
80 ////////////////////////////////////////////////////////////////////
81 // Implementation of org.xml.sax.Attributes.
82 ////////////////////////////////////////////////////////////////////
86 * Return the number of attributes in the list.
88 * @return The number of attributes in the list.
89 * @see org.xml.sax.Attributes#getLength
92 public int getLength ()
99 * Return an attribute's Namespace URI.
101 * @param index The attribute's index (zero-based).
102 * @return The Namespace URI, the empty string if none is
103 * available, or null if the index is out of range.
104 * @see org.xml.sax.Attributes#getURI
107 public String getURI (int index)
109 if (index >= 0 && index < length) {
110 return data[index*5];
118 * Return an attribute's local name.
120 * @param index The attribute's index (zero-based).
121 * @return The attribute's local name, the empty string if
122 * none is available, or null if the index if out of range.
123 * @see org.xml.sax.Attributes#getLocalName
126 public String getLocalName (int index)
128 if (index >= 0 && index < length) {
129 return data[index*5+1];
137 * Return an attribute's qualified (prefixed) name.
139 * @param index The attribute's index (zero-based).
140 * @return The attribute's qualified name, the empty string if
141 * none is available, or null if the index is out of bounds.
142 * @see org.xml.sax.Attributes#getQName
145 public String getQName (int index)
147 if (index >= 0 && index < length) {
148 return data[index*5+2];
156 * Return an attribute's type by index.
158 * @param index The attribute's index (zero-based).
159 * @return The attribute's type, "CDATA" if the type is unknown, or null
160 * if the index is out of bounds.
161 * @see org.xml.sax.Attributes#getType(int)
164 public String getType (int index)
166 if (index >= 0 && index < length) {
167 return data[index*5+3];
175 * Return an attribute's value by index.
177 * @param index The attribute's index (zero-based).
178 * @return The attribute's value or null if the index is out of bounds.
179 * @see org.xml.sax.Attributes#getValue(int)
182 public String getValue (int index)
184 if (index >= 0 && index < length) {
185 return data[index*5+4];
193 * Look up an attribute's index by Namespace name.
195 * <p>In many cases, it will be more efficient to look up the name once and
196 * use the index query methods rather than using the name query methods
199 * @param uri The attribute's Namespace URI, or the empty
200 * string if none is available.
201 * @param localName The attribute's local name.
202 * @return The attribute's index, or -1 if none matches.
203 * @see org.xml.sax.Attributes#getIndex(java.lang.String,java.lang.String)
206 public int getIndex (String uri, String localName)
208 int max = length * 5;
209 for (int i = 0; i < max; i += 5) {
210 if (data[i].equals(uri) && data[i+1].equals(localName)) {
219 * Look up an attribute's index by qualified (prefixed) name.
221 * @param qName The qualified name.
222 * @return The attribute's index, or -1 if none matches.
223 * @see org.xml.sax.Attributes#getIndex(java.lang.String)
226 public int getIndex (String qName)
228 int max = length * 5;
229 for (int i = 0; i < max; i += 5) {
230 if (data[i+2].equals(qName)) {
239 * Look up an attribute's type by Namespace-qualified name.
241 * @param uri The Namespace URI, or the empty string for a name
242 * with no explicit Namespace URI.
243 * @param localName The local name.
244 * @return The attribute's type, or null if there is no
245 * matching attribute.
246 * @see org.xml.sax.Attributes#getType(java.lang.String,java.lang.String)
249 public String getType (String uri, String localName)
251 int max = length * 5;
252 for (int i = 0; i < max; i += 5) {
253 if (data[i].equals(uri) && data[i+1].equals(localName)) {
262 * Look up an attribute's type by qualified (prefixed) name.
264 * @param qName The qualified name.
265 * @return The attribute's type, or null if there is no
266 * matching attribute.
267 * @see org.xml.sax.Attributes#getType(java.lang.String)
270 public String getType (String qName)
272 int max = length * 5;
273 for (int i = 0; i < max; i += 5) {
274 if (data[i+2].equals(qName)) {
283 * Look up an attribute's value by Namespace-qualified name.
285 * @param uri The Namespace URI, or the empty string for a name
286 * with no explicit Namespace URI.
287 * @param localName The local name.
288 * @return The attribute's value, or null if there is no
289 * matching attribute.
290 * @see org.xml.sax.Attributes#getValue(java.lang.String,java.lang.String)
293 public String getValue (String uri, String localName)
295 int max = length * 5;
296 for (int i = 0; i < max; i += 5) {
297 if (data[i].equals(uri) && data[i+1].equals(localName)) {
306 * Look up an attribute's value by qualified (prefixed) name.
308 * @param qName The qualified name.
309 * @return The attribute's value, or null if there is no
310 * matching attribute.
311 * @see org.xml.sax.Attributes#getValue(java.lang.String)
314 public String getValue (String qName)
316 int max = length * 5;
317 for (int i = 0; i < max; i += 5) {
318 if (data[i+2].equals(qName)) {
327 ////////////////////////////////////////////////////////////////////
329 ////////////////////////////////////////////////////////////////////
333 * Clear the attribute list for reuse.
335 * <p>Note that little memory is freed by this call:
336 * the current array is kept so it can be
342 for (int i = 0; i < (length * 5); i++)
350 * Copy an entire Attributes object.
352 * <p>It may be more efficient to reuse an existing object
353 * rather than constantly allocating new ones.</p>
355 * @param atts The attributes to copy.
357 public void setAttributes (Attributes atts)
360 length = atts.getLength();
362 data = new String[length*5];
363 for (int i = 0; i < length; i++) {
364 data[i*5] = atts.getURI(i);
365 data[i*5+1] = atts.getLocalName(i);
366 data[i*5+2] = atts.getQName(i);
367 data[i*5+3] = atts.getType(i);
368 data[i*5+4] = atts.getValue(i);
375 * Add an attribute to the end of the list.
377 * <p>For the sake of speed, this method does no checking
378 * to see if the attribute is already in the list: that is
379 * the responsibility of the application.</p>
381 * @param uri The Namespace URI, or the empty string if
382 * none is available or Namespace processing is not
384 * @param localName The local name, or the empty string if
385 * Namespace processing is not being performed.
386 * @param qName The qualified (prefixed) name, or the empty string
387 * if qualified names are not available.
388 * @param type The attribute type as a string.
389 * @param value The attribute value.
391 public void addAttribute (String uri, String localName, String qName,
392 String type, String value)
394 ensureCapacity(length+1);
395 data[length*5] = uri;
396 data[length*5+1] = localName;
397 data[length*5+2] = qName;
398 data[length*5+3] = type;
399 data[length*5+4] = value;
405 * Set an attribute in the list.
407 * <p>For the sake of speed, this method does no checking
408 * for name conflicts or well-formedness: such checks are the
409 * responsibility of the application.</p>
411 * @param index The index of the attribute (zero-based).
412 * @param uri The Namespace URI, or the empty string if
413 * none is available or Namespace processing is not
415 * @param localName The local name, or the empty string if
416 * Namespace processing is not being performed.
417 * @param qName The qualified name, or the empty string
418 * if qualified names are not available.
419 * @param type The attribute type as a string.
420 * @param value The attribute value.
421 * @exception java.lang.ArrayIndexOutOfBoundsException When the
422 * supplied index does not point to an attribute
425 public void setAttribute (int index, String uri, String localName,
426 String qName, String type, String value)
428 if (index >= 0 && index < length) {
430 data[index*5+1] = localName;
431 data[index*5+2] = qName;
432 data[index*5+3] = type;
433 data[index*5+4] = value;
441 * Remove an attribute from the list.
443 * @param index The index of the attribute (zero-based).
444 * @exception java.lang.ArrayIndexOutOfBoundsException When the
445 * supplied index does not point to an attribute
448 public void removeAttribute (int index)
450 if (index >= 0 && index < length) {
451 if (index < length - 1) {
452 System.arraycopy(data, (index+1)*5, data, index*5,
455 index = (length - 1) * 5;
456 data [index++] = null;
457 data [index++] = null;
458 data [index++] = null;
459 data [index++] = null;
469 * Set the Namespace URI of a specific attribute.
471 * @param index The index of the attribute (zero-based).
472 * @param uri The attribute's Namespace URI, or the empty
474 * @exception java.lang.ArrayIndexOutOfBoundsException When the
475 * supplied index does not point to an attribute
478 public void setURI (int index, String uri)
480 if (index >= 0 && index < length) {
489 * Set the local name of a specific attribute.
491 * @param index The index of the attribute (zero-based).
492 * @param localName The attribute's local name, or the empty
494 * @exception java.lang.ArrayIndexOutOfBoundsException When the
495 * supplied index does not point to an attribute
498 public void setLocalName (int index, String localName)
500 if (index >= 0 && index < length) {
501 data[index*5+1] = localName;
509 * Set the qualified name of a specific attribute.
511 * @param index The index of the attribute (zero-based).
512 * @param qName The attribute's qualified name, or the empty
514 * @exception java.lang.ArrayIndexOutOfBoundsException When the
515 * supplied index does not point to an attribute
518 public void setQName (int index, String qName)
520 if (index >= 0 && index < length) {
521 data[index*5+2] = qName;
529 * Set the type of a specific attribute.
531 * @param index The index of the attribute (zero-based).
532 * @param type The attribute's type.
533 * @exception java.lang.ArrayIndexOutOfBoundsException When the
534 * supplied index does not point to an attribute
537 public void setType (int index, String type)
539 if (index >= 0 && index < length) {
540 data[index*5+3] = type;
548 * Set the value of a specific attribute.
550 * @param index The index of the attribute (zero-based).
551 * @param value The attribute's value.
552 * @exception java.lang.ArrayIndexOutOfBoundsException When the
553 * supplied index does not point to an attribute
556 public void setValue (int index, String value)
558 if (index >= 0 && index < length) {
559 data[index*5+4] = value;
567 ////////////////////////////////////////////////////////////////////
569 ////////////////////////////////////////////////////////////////////
573 * Ensure the internal array's capacity.
575 * @param n The minimum number of attributes that the array must
578 private void ensureCapacity (int n) {
583 if (data == null || data.length == 0) {
586 else if (data.length >= n * 5) {
592 while (max < n * 5) {
596 String newData[] = new String[max];
598 System.arraycopy(data, 0, newData, 0, length*5);
605 * Report a bad array index in a manipulator.
607 * @param index The index to report.
608 * @exception java.lang.ArrayIndexOutOfBoundsException Always.
610 private void badIndex (int index)
611 throws ArrayIndexOutOfBoundsException
614 "Attempt to modify attribute at illegal index: " + index;
615 throw new ArrayIndexOutOfBoundsException(msg);
620 ////////////////////////////////////////////////////////////////////
622 ////////////////////////////////////////////////////////////////////
629 // end of AttributesImpl.java