1 // Attributes2Impl.java - extended AttributesImpl
2 // http://www.saxproject.org
3 // Public Domain: no warranty.
4 // $Id: Attributes2Impl.java,v 1.8 2004/12/11 15:41:10 dog Exp $
5 
6 package org.xml.sax.ext;
7 
8 import org.xml.sax.Attributes;
9 import org.xml.sax.helpers.AttributesImpl;
10 
11 
12 /**
13  * SAX2 extension helper for additional Attributes information,
14  * implementing the {@link Attributes2} interface.
15  *
16  * <blockquote>
17  * <em>This module, both source code and documentation, is in the
18  * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
19  * </blockquote>
20  *
21  * <p>This is not part of core-only SAX2 distributions.</p>
22  *
23  * <p>The <em>specified</em> flag for each attribute will always
24  * be true, unless it has been set to false in the copy constructor
25  * or using {@link #setSpecified}.
26  * Similarly, the <em>declared</em> flag for each attribute will
27  * always be false, except for defaulted attributes (<em>specified</em>
28  * is false), non-CDATA attributes, or when it is set to true using
29  * {@link #setDeclared}.
30  * If you change an attribute's type by hand, you may need to modify
31  * its <em>declared</em> flag to match.
32  * </p>
33  *
34  * @since SAX 2.0 (extensions 1.1 alpha)
35  * @author David Brownell
36  * @version TBS
37  */
38 public class Attributes2Impl extends AttributesImpl implements Attributes2
39 {
40     private boolean	declared [];
41     private boolean	specified [];
42 
43 
44     /**
45      * Construct a new, empty Attributes2Impl object.
46      */
Attributes2Impl()47     public Attributes2Impl () { }
48 
49 
50     /**
51      * Copy an existing Attributes or Attributes2 object.
52      * If the object implements Attributes2, values of the
53      * <em>specified</em> and <em>declared</em> flags for each
54      * attribute are copied.
55      * Otherwise the flag values are defaulted to assume no DTD was used,
56      * unless there is evidence to the contrary (such as attributes with
57      * type other than CDATA, which must have been <em>declared</em>).
58      *
59      * <p>This constructor is especially useful inside a
60      * {@link org.xml.sax.ContentHandler#startElement startElement} event.</p>
61      *
62      * @param atts The existing Attributes object.
63      */
Attributes2Impl(Attributes atts)64     public Attributes2Impl (Attributes atts)
65     {
66 	super (atts);
67     }
68 
69 
70     ////////////////////////////////////////////////////////////////////
71     // Implementation of Attributes2
72     ////////////////////////////////////////////////////////////////////
73 
74 
75     /**
76      * Returns the current value of the attribute's "declared" flag.
77      */
78     // javadoc mostly from interface
isDeclared(int index)79     public boolean isDeclared (int index)
80     {
81 	if (index < 0 || index >= getLength ())
82 	    throw new ArrayIndexOutOfBoundsException (
83 		"No attribute at index: " + index);
84 	return declared [index];
85     }
86 
87 
88     /**
89      * Returns the current value of the attribute's "declared" flag.
90      */
91     // javadoc mostly from interface
isDeclared(String uri, String localName)92     public boolean isDeclared (String uri, String localName)
93     {
94 	int index = getIndex (uri, localName);
95 
96 	if (index < 0)
97 	    throw new IllegalArgumentException (
98 		"No such attribute: local=" + localName
99 		+ ", namespace=" + uri);
100 	return declared [index];
101     }
102 
103 
104     /**
105      * Returns the current value of the attribute's "declared" flag.
106      */
107     // javadoc mostly from interface
isDeclared(String qName)108     public boolean isDeclared (String qName)
109     {
110 	int index = getIndex (qName);
111 
112 	if (index < 0)
113 	    throw new IllegalArgumentException (
114 		"No such attribute: " + qName);
115 	return declared [index];
116     }
117 
118 
119     /**
120      * Returns the current value of an attribute's "specified" flag.
121      *
122      * @param index The attribute index (zero-based).
123      * @return current flag value
124      * @exception java.lang.ArrayIndexOutOfBoundsException When the
125      *            supplied index does not identify an attribute.
126      */
isSpecified(int index)127     public boolean isSpecified (int index)
128     {
129 	if (index < 0 || index >= getLength ())
130 	    throw new ArrayIndexOutOfBoundsException (
131 		"No attribute at index: " + index);
132 	return specified [index];
133     }
134 
135 
136     /**
137      * Returns the current value of an attribute's "specified" flag.
138      *
139      * @param uri The Namespace URI, or the empty string if
140      *        the name has no Namespace URI.
141      * @param localName The attribute's local name.
142      * @return current flag value
143      * @exception java.lang.IllegalArgumentException When the
144      *            supplied names do not identify an attribute.
145      */
isSpecified(String uri, String localName)146     public boolean isSpecified (String uri, String localName)
147     {
148 	int index = getIndex (uri, localName);
149 
150 	if (index < 0)
151 	    throw new IllegalArgumentException (
152 		"No such attribute: local=" + localName
153 		+ ", namespace=" + uri);
154 	return specified [index];
155     }
156 
157 
158     /**
159      * Returns the current value of an attribute's "specified" flag.
160      *
161      * @param qName The XML qualified (prefixed) name.
162      * @return current flag value
163      * @exception java.lang.IllegalArgumentException When the
164      *            supplied name does not identify an attribute.
165      */
isSpecified(String qName)166     public boolean isSpecified (String qName)
167     {
168 	int index = getIndex (qName);
169 
170 	if (index < 0)
171 	    throw new IllegalArgumentException (
172 		"No such attribute: " + qName);
173 	return specified [index];
174     }
175 
176 
177     ////////////////////////////////////////////////////////////////////
178     // Manipulators
179     ////////////////////////////////////////////////////////////////////
180 
181 
182     /**
183      * Copy an entire Attributes object.  The "specified" flags are
184      * assigned as true, and "declared" flags as false (except when
185      * an attribute's type is not CDATA),
186      * unless the object is an Attributes2 object.
187      * In that case those flag values are all copied.
188      *
189      * @see AttributesImpl#setAttributes
190      */
setAttributes(Attributes atts)191     public void setAttributes (Attributes atts)
192     {
193 	int length = atts.getLength ();
194 
195 	super.setAttributes (atts);
196 	declared = new boolean [length];
197 	specified = new boolean [length];
198 
199 	if (atts instanceof Attributes2) {
200 	    Attributes2	a2 = (Attributes2) atts;
201 	    for (int i = 0; i < length; i++) {
202 		declared [i] = a2.isDeclared (i);
203 		specified [i] = a2.isSpecified (i);
204 	    }
205 	} else {
206 	    for (int i = 0; i < length; i++) {
207 		declared [i] = !"CDATA".equals (atts.getType (i));
208 		specified [i] = true;
209 	    }
210 	}
211     }
212 
213 
214     /**
215      * Add an attribute to the end of the list, setting its
216      * "specified" flag to true.  To set that flag's value
217      * to false, use {@link #setSpecified}.
218      *
219      * <p>Unless the attribute <em>type</em> is CDATA, this attribute
220      * is marked as being declared in the DTD.  To set that flag's value
221      * to true for CDATA attributes, use {@link #setDeclared}.
222      *
223      * @see AttributesImpl#addAttribute
224      */
addAttribute(String uri, String localName, String qName, String type, String value)225     public void addAttribute (String uri, String localName, String qName,
226 			      String type, String value)
227     {
228 	super.addAttribute (uri, localName, qName, type, value);
229 
230 	int length = getLength ();
231 
232 	if (length < specified.length) {
233 	    boolean	newFlags [];
234 
235 	    newFlags = new boolean [length];
236 	    System.arraycopy (declared, 0, newFlags, 0, declared.length);
237 	    declared = newFlags;
238 
239 	    newFlags = new boolean [length];
240 	    System.arraycopy (specified, 0, newFlags, 0, specified.length);
241 	    specified = newFlags;
242 	}
243 
244 	specified [length - 1] = true;
245 	declared [length - 1] = !"CDATA".equals (type);
246     }
247 
248 
249     // javadoc entirely from superclass
removeAttribute(int index)250     public void removeAttribute (int index)
251     {
252 	int origMax = getLength () - 1;
253 
254 	super.removeAttribute (index);
255 	if (index != origMax) {
256 	    System.arraycopy (declared, index + 1, declared, index,
257 		    origMax - index);
258 	    System.arraycopy (specified, index + 1, specified, index,
259 		    origMax - index);
260 	}
261     }
262 
263 
264     /**
265      * Assign a value to the "declared" flag of a specific attribute.
266      * This is normally needed only for attributes of type CDATA,
267      * including attributes whose type is changed to or from CDATA.
268      *
269      * @param index The index of the attribute (zero-based).
270      * @param value The desired flag value.
271      * @exception java.lang.ArrayIndexOutOfBoundsException When the
272      *            supplied index does not identify an attribute.
273      * @see #setType
274      */
setDeclared(int index, boolean value)275     public void setDeclared (int index, boolean value)
276     {
277 	if (index < 0 || index >= getLength ())
278 	    throw new ArrayIndexOutOfBoundsException (
279 		"No attribute at index: " + index);
280 	declared [index] = value;
281     }
282 
283 
284     /**
285      * Assign a value to the "specified" flag of a specific attribute.
286      * This is the only way this flag can be cleared, except clearing
287      * by initialization with the copy constructor.
288      *
289      * @param index The index of the attribute (zero-based).
290      * @param value The desired flag value.
291      * @exception java.lang.ArrayIndexOutOfBoundsException When the
292      *            supplied index does not identify an attribute.
293      */
setSpecified(int index, boolean value)294     public void setSpecified (int index, boolean value)
295     {
296 	if (index < 0 || index >= getLength ())
297 	    throw new ArrayIndexOutOfBoundsException (
298 		"No attribute at index: " + index);
299 	specified [index] = value;
300     }
301 }
302