1 /*
2 * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26 // AttributesImpl.java - default implementation of Attributes.
27 // Written by David Megginson, sax@megginson.com
28 // NO WARRANTY! This class is in the public domain.
29
30 // $Id: AttributesImpl.java,v 1.4 2002/09/29 02:55:48 okajima Exp $
31
32 //fixed bug at removeAttribute!! by Daisuke OKAJIMA 2002.4.21
33
34 package com.sun.xml.internal.xsom.impl.parser.state;
35
36 import org.xml.sax.Attributes;
37
38
39 /**
40 * Default implementation of the Attributes interface.
41 *
42 * <blockquote>
43 * <em>This module, both source code and documentation, is in the
44 * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
45 * </blockquote>
46 *
47 * <p>This class provides a default implementation of the SAX2
48 * {@link org.xml.sax.Attributes Attributes} interface, with the
49 * addition of manipulators so that the list can be modified or
50 * reused.</p>
51 *
52 * <p>There are two typical uses of this class:</p>
53 *
54 * <ol>
55 * <li>to take a persistent snapshot of an Attributes object
56 * in a {@link org.xml.sax.ContentHandler#startElement startElement} event; or</li>
57 * <li>to construct or modify an Attributes object in a SAX2 driver or filter.</li>
58 * </ol>
59 *
60 * <p>This class replaces the now-deprecated SAX1 {@link
61 * org.xml.sax.helpers.AttributeListImpl AttributeListImpl}
62 * class; in addition to supporting the updated Attributes
63 * interface rather than the deprecated {@link org.xml.sax.AttributeList
64 * AttributeList} interface, it also includes a much more efficient
65 * implementation using a single array rather than a set of Vectors.</p>
66 *
67 * @since SAX 2.0
68 * @author David Megginson,
69 * <a href="mailto:sax@megginson.com">sax@megginson.com</a>
70 */
71 public class AttributesImpl implements Attributes
72 {
73
74
75 ////////////////////////////////////////////////////////////////////
76 // Constructors.
77 ////////////////////////////////////////////////////////////////////
78
79
80 /**
81 * Construct a new, empty AttributesImpl object.
82 */
83 public AttributesImpl ()
84 {
85 length = 0;
86 data = null;
87 }
88
89
90 /**
91 * Copy an existing Attributes object.
92 *
93 * <p>This constructor is especially useful inside a
94 * {@link org.xml.sax.ContentHandler#startElement startElement} event.</p>
95 *
96 * @param atts The existing Attributes object.
97 */
98 public AttributesImpl (Attributes atts)
99 {
100 setAttributes(atts);
101 }
102
103
104
105 ////////////////////////////////////////////////////////////////////
106 // Implementation of org.xml.sax.Attributes.
107 ////////////////////////////////////////////////////////////////////
108
109
110 /**
111 * Return the number of attributes in the list.
112 *
113 * @return The number of attributes in the list.
114 * @see org.xml.sax.Attributes#getLength
115 */
116 public int getLength ()
117 {
118 return length;
119 }
120
121
122 /**
123 * Return an attribute's Namespace URI.
124 *
125 * @param index The attribute's index (zero-based).
126 * @return The Namespace URI, the empty string if none is
127 * available, or null if the index is out of range.
128 * @see org.xml.sax.Attributes#getURI
129 */
130 public String getURI (int index)
131 {
132 if (index >= 0 && index < length) {
133 return data[index*5];
134 } else {
135 return null;
136 }
137 }
138
139
140 /**
141 * Return an attribute's local name.
142 *
143 * @param index The attribute's index (zero-based).
144 * @return The attribute's local name, the empty string if
145 * none is available, or null if the index if out of range.
146 * @see org.xml.sax.Attributes#getLocalName
147 */
148 public String getLocalName (int index)
149 {
150 if (index >= 0 && index < length) {
151 return data[index*5+1];
152 } else {
153 return null;
154 }
155 }
156
157
158 /**
159 * Return an attribute's qualified (prefixed) name.
160 *
161 * @param index The attribute's index (zero-based).
162 * @return The attribute's qualified name, the empty string if
163 * none is available, or null if the index is out of bounds.
164 * @see org.xml.sax.Attributes#getQName
165 */
166 public String getQName (int index)
167 {
168 if (index >= 0 && index < length) {
169 return data[index*5+2];
170 } else {
171 return null;
172 }
173 }
174
175
176 /**
177 * Return an attribute's type by index.
178 *
179 * @param index The attribute's index (zero-based).
180 * @return The attribute's type, "CDATA" if the type is unknown, or null
181 * if the index is out of bounds.
182 * @see org.xml.sax.Attributes#getType(int)
183 */
184 public String getType (int index)
185 {
186 if (index >= 0 && index < length) {
187 return data[index*5+3];
188 } else {
189 return null;
190 }
191 }
192
193
194 /**
195 * Return an attribute's value by index.
196 *
197 * @param index The attribute's index (zero-based).
198 * @return The attribute's value or null if the index is out of bounds.
199 * @see org.xml.sax.Attributes#getValue(int)
200 */
201 public String getValue (int index)
202 {
203 if (index >= 0 && index < length) {
204 return data[index*5+4];
205 } else {
206 return null;
207 }
208 }
209
210
211 /**
212 * Look up an attribute's index by Namespace name.
213 *
214 * <p>In many cases, it will be more efficient to look up the name once and
215 * use the index query methods rather than using the name query methods
216 * repeatedly.</p>
217 *
218 * @param uri The attribute's Namespace URI, or the empty
219 * string if none is available.
220 * @param localName The attribute's local name.
221 * @return The attribute's index, or -1 if none matches.
222 * @see org.xml.sax.Attributes#getIndex(java.lang.String,java.lang.String)
223 */
224 public int getIndex (String uri, String localName)
225 {
226 int max = length * 5;
227 for (int i = 0; i < max; i += 5) {
228 if (data[i].equals(uri) && data[i+1].equals(localName)) {
229 return i / 5;
230 }
231 }
232 return -1;
233 }
234
235
236 /**
237 * Look up an attribute's index by qualified (prefixed) name.
238 *
239 * @param qName The qualified name.
240 * @return The attribute's index, or -1 if none matches.
241 * @see org.xml.sax.Attributes#getIndex(java.lang.String)
242 */
243 public int getIndex (String qName)
244 {
245 int max = length * 5;
246 for (int i = 0; i < max; i += 5) {
247 if (data[i+2].equals(qName)) {
248 return i / 5;
249 }
250 }
251 return -1;
252 }
253
254
255 /**
256 * Look up an attribute's type by Namespace-qualified name.
257 *
258 * @param uri The Namespace URI, or the empty string for a name
259 * with no explicit Namespace URI.
260 * @param localName The local name.
261 * @return The attribute's type, or null if there is no
262 * matching attribute.
263 * @see org.xml.sax.Attributes#getType(java.lang.String,java.lang.String)
264 */
265 public String getType (String uri, String localName)
266 {
267 int max = length * 5;
268 for (int i = 0; i < max; i += 5) {
269 if (data[i].equals(uri) && data[i+1].equals(localName)) {
270 return data[i+3];
271 }
272 }
273 return null;
274 }
275
276
277 /**
278 * Look up an attribute's type by qualified (prefixed) name.
279 *
280 * @param qName The qualified name.
281 * @return The attribute's type, or null if there is no
282 * matching attribute.
283 * @see org.xml.sax.Attributes#getType(java.lang.String)
284 */
285 public String getType (String qName)
286 {
287 int max = length * 5;
288 for (int i = 0; i < max; i += 5) {
289 if (data[i+2].equals(qName)) {
290 return data[i+3];
291 }
292 }
293 return null;
294 }
295
296
297 /**
298 * Look up an attribute's value by Namespace-qualified name.
299 *
300 * @param uri The Namespace URI, or the empty string for a name
301 * with no explicit Namespace URI.
302 * @param localName The local name.
303 * @return The attribute's value, or null if there is no
304 * matching attribute.
305 * @see org.xml.sax.Attributes#getValue(java.lang.String,java.lang.String)
306 */
307 public String getValue (String uri, String localName)
308 {
309 int max = length * 5;
310 for (int i = 0; i < max; i += 5) {
311 if (data[i].equals(uri) && data[i+1].equals(localName)) {
312 return data[i+4];
313 }
314 }
315 return null;
316 }
317
318
319 /**
320 * Look up an attribute's value by qualified (prefixed) name.
321 *
322 * @param qName The qualified name.
323 * @return The attribute's value, or null if there is no
324 * matching attribute.
325 * @see org.xml.sax.Attributes#getValue(java.lang.String)
326 */
327 public String getValue (String qName)
328 {
329 int max = length * 5;
330 for (int i = 0; i < max; i += 5) {
331 if (data[i+2].equals(qName)) {
332 return data[i+4];
333 }
334 }
335 return null;
336 }
337
338
339
340 ////////////////////////////////////////////////////////////////////
341 // Manipulators.
342 ////////////////////////////////////////////////////////////////////
343
344
345 /**
346 * Clear the attribute list for reuse.
347 *
348 * <p>Note that no memory is actually freed by this call:
349 * the current arrays are kept so that they can be
350 * reused.</p>
351 */
352 public void clear ()
353 {
354 length = 0;
355 }
356
357
358 /**
359 * Copy an entire Attributes object.
360 *
361 * <p>It may be more efficient to reuse an existing object
362 * rather than constantly allocating new ones.</p>
363 *
364 * @param atts The attributes to copy.
365 */
366 public void setAttributes (Attributes atts)
367 {
368 clear();
369 length = atts.getLength();
370 data = new String[length*5];
371 for (int i = 0; i < length; i++) {
372 data[i*5] = atts.getURI(i);
373 data[i*5+1] = atts.getLocalName(i);
374 data[i*5+2] = atts.getQName(i);
375 data[i*5+3] = atts.getType(i);
376 data[i*5+4] = atts.getValue(i);
377 }
378 }
379
380
381 /**
382 * Add an attribute to the end of the list.
383 *
384 * <p>For the sake of speed, this method does no checking
385 * to see if the attribute is already in the list: that is
386 * the responsibility of the application.</p>
387 *
388 * @param uri The Namespace URI, or the empty string if
389 * none is available or Namespace processing is not
390 * being performed.
391 * @param localName The local name, or the empty string if
392 * Namespace processing is not being performed.
393 * @param qName The qualified (prefixed) name, or the empty string
394 * if qualified names are not available.
395 * @param type The attribute type as a string.
396 * @param value The attribute value.
397 */
398 public void addAttribute (String uri, String localName, String qName,
399 String type, String value)
400 {
401 ensureCapacity(length+1);
402 data[length*5] = uri;
403 data[length*5+1] = localName;
404 data[length*5+2] = qName;
405 data[length*5+3] = type;
406 data[length*5+4] = value;
407 length++;
408 }
409
410
411 /**
412 * Set an attribute in the list.
413 *
414 * <p>For the sake of speed, this method does no checking
415 * for name conflicts or well-formedness: such checks are the
416 * responsibility of the application.</p>
417 *
418 * @param index The index of the attribute (zero-based).
419 * @param uri The Namespace URI, or the empty string if
420 * none is available or Namespace processing is not
421 * being performed.
422 * @param localName The local name, or the empty string if
423 * Namespace processing is not being performed.
424 * @param qName The qualified name, or the empty string
425 * if qualified names are not available.
426 * @param type The attribute type as a string.
427 * @param value The attribute value.
428 * @exception java.lang.ArrayIndexOutOfBoundsException When the
429 * supplied index does not point to an attribute
430 * in the list.
431 */
432 public void setAttribute (int index, String uri, String localName,
433 String qName, String type, String value)
434 {
435 if (index >= 0 && index < length) {
436 data[index*5] = uri;
437 data[index*5+1] = localName;
438 data[index*5+2] = qName;
439 data[index*5+3] = type;
440 data[index*5+4] = value;
441 } else {
442 badIndex(index);
443 }
444 }
445
446
447 /**
448 * Remove an attribute from the list.
449 *
450 * @param index The index of the attribute (zero-based).
451 * @exception java.lang.ArrayIndexOutOfBoundsException When the
452 * supplied index does not point to an attribute
453 * in the list.
454 */
455 public void removeAttribute (int index)
456 {
457 if (index >= 0 && index < length) {
458 if (index < length - 1) {
459 System.arraycopy(data, (index+1)*5, data, index*5,
460 (length-index-1)*5);
461 }
462 length--;
463 } else {
464 badIndex(index);
465 }
466 }
467
468
469 /**
470 * Set the Namespace URI of a specific attribute.
471 *
472 * @param index The index of the attribute (zero-based).
473 * @param uri The attribute's Namespace URI, or the empty
474 * string for none.
475 * @exception java.lang.ArrayIndexOutOfBoundsException When the
476 * supplied index does not point to an attribute
477 * in the list.
478 */
479 public void setURI (int index, String uri)
480 {
481 if (index >= 0 && index < length) {
482 data[index*5] = uri;
483 } else {
484 badIndex(index);
485 }
486 }
487
488
489 /**
490 * Set the local name of a specific attribute.
491 *
492 * @param index The index of the attribute (zero-based).
493 * @param localName The attribute's local name, or the empty
494 * string for none.
495 * @exception java.lang.ArrayIndexOutOfBoundsException When the
496 * supplied index does not point to an attribute
497 * in the list.
498 */
499 public void setLocalName (int index, String localName)
500 {
501 if (index >= 0 && index < length) {
502 data[index*5+1] = localName;
503 } else {
504 badIndex(index);
505 }
506 }
507
508
509 /**
510 * Set the qualified name of a specific attribute.
511 *
512 * @param index The index of the attribute (zero-based).
513 * @param qName The attribute's qualified name, or the empty
514 * string for none.
515 * @exception java.lang.ArrayIndexOutOfBoundsException When the
516 * supplied index does not point to an attribute
517 * in the list.
518 */
519 public void setQName (int index, String qName)
520 {
521 if (index >= 0 && index < length) {
522 data[index*5+2] = qName;
523 } else {
524 badIndex(index);
525 }
526 }
527
528
529 /**
530 * Set the type of a specific attribute.
531 *
532 * @param index The index of the attribute (zero-based).
533 * @param type The attribute's type.
534 * @exception java.lang.ArrayIndexOutOfBoundsException When the
535 * supplied index does not point to an attribute
536 * in the list.
537 */
538 public void setType (int index, String type)
539 {
540 if (index >= 0 && index < length) {
541 data[index*5+3] = type;
542 } else {
543 badIndex(index);
544 }
545 }
546
547
548 /**
549 * Set the value of a specific attribute.
550 *
551 * @param index The index of the attribute (zero-based).
552 * @param value The attribute's value.
553 * @exception java.lang.ArrayIndexOutOfBoundsException When the
554 * supplied index does not point to an attribute
555 * in the list.
556 */
557 public void setValue (int index, String value)
558 {
559 if (index >= 0 && index < length) {
560 data[index*5+4] = value;
561 } else {
562 badIndex(index);
563 }
564 }
565
566
567
568 ////////////////////////////////////////////////////////////////////
569 // Internal methods.
570 ////////////////////////////////////////////////////////////////////
571
572
573 /**
574 * Ensure the internal array's capacity.
575 *
576 * @param n The minimum number of attributes that the array must
577 * be able to hold.
578 */
579 private void ensureCapacity (int n)
580 {
581 if (n > 0 && (data == null || data.length==0)) {
582 data = new String[25];
583 }
584
585 int max = data.length;
586 if (max >= n * 5) {
587 return;
588 }
589
590
591 while (max < n * 5) {
592 max *= 2;
593 }
594 String newData[] = new String[max];
595 System.arraycopy(data, 0, newData, 0, length*5);
596 data = newData;
597 }
598
599
600 /**
601 * Report a bad array index in a manipulator.
602 *
603 * @param index The index to report.
604 * @exception java.lang.ArrayIndexOutOfBoundsException Always.
605 */
606 private void badIndex (int index)
607 throws ArrayIndexOutOfBoundsException
608 {
609 String msg =
610 "Attempt to modify attribute at illegal index: " + index;
611 throw new ArrayIndexOutOfBoundsException(msg);
612 }
613
614
615
616 ////////////////////////////////////////////////////////////////////
617 // Internal state.
618 ////////////////////////////////////////////////////////////////////
619
620 int length;
621 String data [];
622
623 }
624
625 // end of AttributesImpl.java