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