001: // AttributesImpl.java - default implementation of Attributes.
002: // Written by David Megginson, sax@megginson.com
003: // NO WARRANTY! This class is in the public domain.
004:
005: // $Id: AttributesImpl.java,v 1.4 2002/09/29 02:55:48 okajima Exp $
006:
007: //fixed bug at removeAttribute!! by Daisuke OKAJIMA 2002.4.21
008:
009: package com.sun.xml.xsom.impl.parser.state;
010:
011: import org.xml.sax.Attributes;
012:
013: /**
014: * Default implementation of the Attributes interface.
015: *
016: * <blockquote>
017: * <em>This module, both source code and documentation, is in the
018: * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
019: * </blockquote>
020: *
021: * <p>This class provides a default implementation of the SAX2
022: * {@link org.xml.sax.Attributes Attributes} interface, with the
023: * addition of manipulators so that the list can be modified or
024: * reused.</p>
025: *
026: * <p>There are two typical uses of this class:</p>
027: *
028: * <ol>
029: * <li>to take a persistent snapshot of an Attributes object
030: * in a {@link org.xml.sax.ContentHandler#startElement startElement} event; or</li>
031: * <li>to construct or modify an Attributes object in a SAX2 driver or filter.</li>
032: * </ol>
033: *
034: * <p>This class replaces the now-deprecated SAX1 {@link
035: * org.xml.sax.helpers.AttributeListImpl AttributeListImpl}
036: * class; in addition to supporting the updated Attributes
037: * interface rather than the deprecated {@link org.xml.sax.AttributeList
038: * AttributeList} interface, it also includes a much more efficient
039: * implementation using a single array rather than a set of Vectors.</p>
040: *
041: * @since SAX 2.0
042: * @author David Megginson,
043: * <a href="mailto:sax@megginson.com">sax@megginson.com</a>
044: * @version 2.0
045: */
046: public class AttributesImpl implements Attributes {
047:
048: ////////////////////////////////////////////////////////////////////
049: // Constructors.
050: ////////////////////////////////////////////////////////////////////
051:
052: /**
053: * Construct a new, empty AttributesImpl object.
054: */
055: public AttributesImpl() {
056: length = 0;
057: data = null;
058: }
059:
060: /**
061: * Copy an existing Attributes object.
062: *
063: * <p>This constructor is especially useful inside a
064: * {@link org.xml.sax.ContentHandler#startElement startElement} event.</p>
065: *
066: * @param atts The existing Attributes object.
067: */
068: public AttributesImpl(Attributes atts) {
069: setAttributes(atts);
070: }
071:
072: ////////////////////////////////////////////////////////////////////
073: // Implementation of org.xml.sax.Attributes.
074: ////////////////////////////////////////////////////////////////////
075:
076: /**
077: * Return the number of attributes in the list.
078: *
079: * @return The number of attributes in the list.
080: * @see org.xml.sax.Attributes#getLength
081: */
082: public int getLength() {
083: return length;
084: }
085:
086: /**
087: * Return an attribute's Namespace URI.
088: *
089: * @param index The attribute's index (zero-based).
090: * @return The Namespace URI, the empty string if none is
091: * available, or null if the index is out of range.
092: * @see org.xml.sax.Attributes#getURI
093: */
094: public String getURI(int index) {
095: if (index >= 0 && index < length) {
096: return data[index * 5];
097: } else {
098: return null;
099: }
100: }
101:
102: /**
103: * Return an attribute's local name.
104: *
105: * @param index The attribute's index (zero-based).
106: * @return The attribute's local name, the empty string if
107: * none is available, or null if the index if out of range.
108: * @see org.xml.sax.Attributes#getLocalName
109: */
110: public String getLocalName(int index) {
111: if (index >= 0 && index < length) {
112: return data[index * 5 + 1];
113: } else {
114: return null;
115: }
116: }
117:
118: /**
119: * Return an attribute's qualified (prefixed) name.
120: *
121: * @param index The attribute's index (zero-based).
122: * @return The attribute's qualified name, the empty string if
123: * none is available, or null if the index is out of bounds.
124: * @see org.xml.sax.Attributes#getQName
125: */
126: public String getQName(int index) {
127: if (index >= 0 && index < length) {
128: return data[index * 5 + 2];
129: } else {
130: return null;
131: }
132: }
133:
134: /**
135: * Return an attribute's type by index.
136: *
137: * @param index The attribute's index (zero-based).
138: * @return The attribute's type, "CDATA" if the type is unknown, or null
139: * if the index is out of bounds.
140: * @see org.xml.sax.Attributes#getType(int)
141: */
142: public String getType(int index) {
143: if (index >= 0 && index < length) {
144: return data[index * 5 + 3];
145: } else {
146: return null;
147: }
148: }
149:
150: /**
151: * Return an attribute's value by index.
152: *
153: * @param index The attribute's index (zero-based).
154: * @return The attribute's value or null if the index is out of bounds.
155: * @see org.xml.sax.Attributes#getValue(int)
156: */
157: public String getValue(int index) {
158: if (index >= 0 && index < length) {
159: return data[index * 5 + 4];
160: } else {
161: return null;
162: }
163: }
164:
165: /**
166: * Look up an attribute's index by Namespace name.
167: *
168: * <p>In many cases, it will be more efficient to look up the name once and
169: * use the index query methods rather than using the name query methods
170: * repeatedly.</p>
171: *
172: * @param uri The attribute's Namespace URI, or the empty
173: * string if none is available.
174: * @param localName The attribute's local name.
175: * @return The attribute's index, or -1 if none matches.
176: * @see org.xml.sax.Attributes#getIndex(java.lang.String,java.lang.String)
177: */
178: public int getIndex(String uri, String localName) {
179: int max = length * 5;
180: for (int i = 0; i < max; i += 5) {
181: if (data[i].equals(uri) && data[i + 1].equals(localName)) {
182: return i / 5;
183: }
184: }
185: return -1;
186: }
187:
188: /**
189: * Look up an attribute's index by qualified (prefixed) name.
190: *
191: * @param qName The qualified name.
192: * @return The attribute's index, or -1 if none matches.
193: * @see org.xml.sax.Attributes#getIndex(java.lang.String)
194: */
195: public int getIndex(String qName) {
196: int max = length * 5;
197: for (int i = 0; i < max; i += 5) {
198: if (data[i + 2].equals(qName)) {
199: return i / 5;
200: }
201: }
202: return -1;
203: }
204:
205: /**
206: * Look up an attribute's type by Namespace-qualified name.
207: *
208: * @param uri The Namespace URI, or the empty string for a name
209: * with no explicit Namespace URI.
210: * @param localName The local name.
211: * @return The attribute's type, or null if there is no
212: * matching attribute.
213: * @see org.xml.sax.Attributes#getType(java.lang.String,java.lang.String)
214: */
215: public String getType(String uri, String localName) {
216: int max = length * 5;
217: for (int i = 0; i < max; i += 5) {
218: if (data[i].equals(uri) && data[i + 1].equals(localName)) {
219: return data[i + 3];
220: }
221: }
222: return null;
223: }
224:
225: /**
226: * Look up an attribute's type by qualified (prefixed) name.
227: *
228: * @param qName The qualified name.
229: * @return The attribute's type, or null if there is no
230: * matching attribute.
231: * @see org.xml.sax.Attributes#getType(java.lang.String)
232: */
233: public String getType(String qName) {
234: int max = length * 5;
235: for (int i = 0; i < max; i += 5) {
236: if (data[i + 2].equals(qName)) {
237: return data[i + 3];
238: }
239: }
240: return null;
241: }
242:
243: /**
244: * Look up an attribute's value by Namespace-qualified name.
245: *
246: * @param uri The Namespace URI, or the empty string for a name
247: * with no explicit Namespace URI.
248: * @param localName The local name.
249: * @return The attribute's value, or null if there is no
250: * matching attribute.
251: * @see org.xml.sax.Attributes#getValue(java.lang.String,java.lang.String)
252: */
253: public String getValue(String uri, String localName) {
254: int max = length * 5;
255: for (int i = 0; i < max; i += 5) {
256: if (data[i].equals(uri) && data[i + 1].equals(localName)) {
257: return data[i + 4];
258: }
259: }
260: return null;
261: }
262:
263: /**
264: * Look up an attribute's value by qualified (prefixed) name.
265: *
266: * @param qName The qualified name.
267: * @return The attribute's value, or null if there is no
268: * matching attribute.
269: * @see org.xml.sax.Attributes#getValue(java.lang.String)
270: */
271: public String getValue(String qName) {
272: int max = length * 5;
273: for (int i = 0; i < max; i += 5) {
274: if (data[i + 2].equals(qName)) {
275: return data[i + 4];
276: }
277: }
278: return null;
279: }
280:
281: ////////////////////////////////////////////////////////////////////
282: // Manipulators.
283: ////////////////////////////////////////////////////////////////////
284:
285: /**
286: * Clear the attribute list for reuse.
287: *
288: * <p>Note that no memory is actually freed by this call:
289: * the current arrays are kept so that they can be
290: * reused.</p>
291: */
292: public void clear() {
293: length = 0;
294: }
295:
296: /**
297: * Copy an entire Attributes object.
298: *
299: * <p>It may be more efficient to reuse an existing object
300: * rather than constantly allocating new ones.</p>
301: *
302: * @param atts The attributes to copy.
303: */
304: public void setAttributes(Attributes atts) {
305: clear();
306: length = atts.getLength();
307: data = new String[length * 5];
308: for (int i = 0; i < length; i++) {
309: data[i * 5] = atts.getURI(i);
310: data[i * 5 + 1] = atts.getLocalName(i);
311: data[i * 5 + 2] = atts.getQName(i);
312: data[i * 5 + 3] = atts.getType(i);
313: data[i * 5 + 4] = atts.getValue(i);
314: }
315: }
316:
317: /**
318: * Add an attribute to the end of the list.
319: *
320: * <p>For the sake of speed, this method does no checking
321: * to see if the attribute is already in the list: that is
322: * the responsibility of the application.</p>
323: *
324: * @param uri The Namespace URI, or the empty string if
325: * none is available or Namespace processing is not
326: * being performed.
327: * @param localName The local name, or the empty string if
328: * Namespace processing is not being performed.
329: * @param qName The qualified (prefixed) name, or the empty string
330: * if qualified names are not available.
331: * @param type The attribute type as a string.
332: * @param value The attribute value.
333: */
334: public void addAttribute(String uri, String localName,
335: String qName, String type, String value) {
336: ensureCapacity(length + 1);
337: data[length * 5] = uri;
338: data[length * 5 + 1] = localName;
339: data[length * 5 + 2] = qName;
340: data[length * 5 + 3] = type;
341: data[length * 5 + 4] = value;
342: length++;
343: }
344:
345: /**
346: * Set an attribute in the list.
347: *
348: * <p>For the sake of speed, this method does no checking
349: * for name conflicts or well-formedness: such checks are the
350: * responsibility of the application.</p>
351: *
352: * @param index The index of the attribute (zero-based).
353: * @param uri The Namespace URI, or the empty string if
354: * none is available or Namespace processing is not
355: * being performed.
356: * @param localName The local name, or the empty string if
357: * Namespace processing is not being performed.
358: * @param qName The qualified name, or the empty string
359: * if qualified names are not available.
360: * @param type The attribute type as a string.
361: * @param value The attribute value.
362: * @exception java.lang.ArrayIndexOutOfBoundsException When the
363: * supplied index does not point to an attribute
364: * in the list.
365: */
366: public void setAttribute(int index, String uri, String localName,
367: String qName, String type, String value) {
368: if (index >= 0 && index < length) {
369: data[index * 5] = uri;
370: data[index * 5 + 1] = localName;
371: data[index * 5 + 2] = qName;
372: data[index * 5 + 3] = type;
373: data[index * 5 + 4] = value;
374: } else {
375: badIndex(index);
376: }
377: }
378:
379: /**
380: * Remove an attribute from the list.
381: *
382: * @param index The index of the attribute (zero-based).
383: * @exception java.lang.ArrayIndexOutOfBoundsException When the
384: * supplied index does not point to an attribute
385: * in the list.
386: */
387: public void removeAttribute(int index) {
388: if (index >= 0 && index < length) {
389: if (index < length - 1) {
390: System.arraycopy(data, (index + 1) * 5, data,
391: index * 5, (length - index - 1) * 5);
392: }
393: length--;
394: } else {
395: badIndex(index);
396: }
397: }
398:
399: /**
400: * Set the Namespace URI of a specific attribute.
401: *
402: * @param index The index of the attribute (zero-based).
403: * @param uri The attribute's Namespace URI, or the empty
404: * string for none.
405: * @exception java.lang.ArrayIndexOutOfBoundsException When the
406: * supplied index does not point to an attribute
407: * in the list.
408: */
409: public void setURI(int index, String uri) {
410: if (index >= 0 && index < length) {
411: data[index * 5] = uri;
412: } else {
413: badIndex(index);
414: }
415: }
416:
417: /**
418: * Set the local name of a specific attribute.
419: *
420: * @param index The index of the attribute (zero-based).
421: * @param localName The attribute's local name, or the empty
422: * string for none.
423: * @exception java.lang.ArrayIndexOutOfBoundsException When the
424: * supplied index does not point to an attribute
425: * in the list.
426: */
427: public void setLocalName(int index, String localName) {
428: if (index >= 0 && index < length) {
429: data[index * 5 + 1] = localName;
430: } else {
431: badIndex(index);
432: }
433: }
434:
435: /**
436: * Set the qualified name of a specific attribute.
437: *
438: * @param index The index of the attribute (zero-based).
439: * @param qName The attribute's qualified name, or the empty
440: * string for none.
441: * @exception java.lang.ArrayIndexOutOfBoundsException When the
442: * supplied index does not point to an attribute
443: * in the list.
444: */
445: public void setQName(int index, String qName) {
446: if (index >= 0 && index < length) {
447: data[index * 5 + 2] = qName;
448: } else {
449: badIndex(index);
450: }
451: }
452:
453: /**
454: * Set the type of a specific attribute.
455: *
456: * @param index The index of the attribute (zero-based).
457: * @param type The attribute's type.
458: * @exception java.lang.ArrayIndexOutOfBoundsException When the
459: * supplied index does not point to an attribute
460: * in the list.
461: */
462: public void setType(int index, String type) {
463: if (index >= 0 && index < length) {
464: data[index * 5 + 3] = type;
465: } else {
466: badIndex(index);
467: }
468: }
469:
470: /**
471: * Set the value of a specific attribute.
472: *
473: * @param index The index of the attribute (zero-based).
474: * @param value The attribute's value.
475: * @exception java.lang.ArrayIndexOutOfBoundsException When the
476: * supplied index does not point to an attribute
477: * in the list.
478: */
479: public void setValue(int index, String value) {
480: if (index >= 0 && index < length) {
481: data[index * 5 + 4] = value;
482: } else {
483: badIndex(index);
484: }
485: }
486:
487: ////////////////////////////////////////////////////////////////////
488: // Internal methods.
489: ////////////////////////////////////////////////////////////////////
490:
491: /**
492: * Ensure the internal array's capacity.
493: *
494: * @param n The minimum number of attributes that the array must
495: * be able to hold.
496: */
497: private void ensureCapacity(int n) {
498: if (n > 0 && (data == null || data.length == 0)) {
499: data = new String[25];
500: }
501:
502: int max = data.length;
503: if (max >= n * 5) {
504: return;
505: }
506:
507: while (max < n * 5) {
508: max *= 2;
509: }
510: String newData[] = new String[max];
511: System.arraycopy(data, 0, newData, 0, length * 5);
512: data = newData;
513: }
514:
515: /**
516: * Report a bad array index in a manipulator.
517: *
518: * @param index The index to report.
519: * @exception java.lang.ArrayIndexOutOfBoundsException Always.
520: */
521: private void badIndex(int index)
522: throws ArrayIndexOutOfBoundsException {
523: String msg = "Attempt to modify attribute at illegal index: "
524: + index;
525: throw new ArrayIndexOutOfBoundsException(msg);
526: }
527:
528: ////////////////////////////////////////////////////////////////////
529: // Internal state.
530: ////////////////////////////////////////////////////////////////////
531:
532: int length;
533: String data[];
534:
535: }
536:
537: // end of AttributesImpl.java
|