001 // Attributes2Impl.java - extended AttributesImpl
002 // http://www.saxproject.org
003 // Public Domain: no warranty.
004 // $Id: Attributes2Impl.java,v 1.1 2004/12/23 22:38:42 mark Exp $
005
006 package org.xml.sax.ext;
007
008 import org.xml.sax.Attributes;
009 import org.xml.sax.helpers.AttributesImpl;
010
011
012 /**
013 * SAX2 extension helper for additional Attributes information,
014 * implementing the {@link Attributes2} 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 is not part of core-only SAX2 distributions.</p>
022 *
023 * <p>The <em>specified</em> flag for each attribute will always
024 * be true, unless it has been set to false in the copy constructor
025 * or using {@link #setSpecified}.
026 * Similarly, the <em>declared</em> flag for each attribute will
027 * always be false, except for defaulted attributes (<em>specified</em>
028 * is false), non-CDATA attributes, or when it is set to true using
029 * {@link #setDeclared}.
030 * If you change an attribute's type by hand, you may need to modify
031 * its <em>declared</em> flag to match.
032 * </p>
033 *
034 * @since SAX 2.0 (extensions 1.1 alpha)
035 * @author David Brownell
036 * @version TBS
037 */
038 public class Attributes2Impl extends AttributesImpl implements Attributes2
039 {
040 private boolean declared [];
041 private boolean specified [];
042
043
044 /**
045 * Construct a new, empty Attributes2Impl object.
046 */
047 public Attributes2Impl () { }
048
049
050 /**
051 * Copy an existing Attributes or Attributes2 object.
052 * If the object implements Attributes2, values of the
053 * <em>specified</em> and <em>declared</em> flags for each
054 * attribute are copied.
055 * Otherwise the flag values are defaulted to assume no DTD was used,
056 * unless there is evidence to the contrary (such as attributes with
057 * type other than CDATA, which must have been <em>declared</em>).
058 *
059 * <p>This constructor is especially useful inside a
060 * {@link org.xml.sax.ContentHandler#startElement startElement} event.</p>
061 *
062 * @param atts The existing Attributes object.
063 */
064 public Attributes2Impl (Attributes atts)
065 {
066 super (atts);
067 }
068
069
070 ////////////////////////////////////////////////////////////////////
071 // Implementation of Attributes2
072 ////////////////////////////////////////////////////////////////////
073
074
075 /**
076 * Returns the current value of the attribute's "declared" flag.
077 */
078 // javadoc mostly from interface
079 public boolean isDeclared (int index)
080 {
081 if (index < 0 || index >= getLength ())
082 throw new ArrayIndexOutOfBoundsException (
083 "No attribute at index: " + index);
084 return declared [index];
085 }
086
087
088 /**
089 * Returns the current value of the attribute's "declared" flag.
090 */
091 // javadoc mostly from interface
092 public boolean isDeclared (String uri, String localName)
093 {
094 int index = getIndex (uri, localName);
095
096 if (index < 0)
097 throw new IllegalArgumentException (
098 "No such attribute: local=" + localName
099 + ", 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
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 */
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 */
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 */
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 */
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 */
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
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 */
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 */
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 }