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    }