KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jdom > Attribute


1 /*--
2
3  $Id: Attribute.java,v 1.52 2004/03/01 23:58:28 jhunter Exp $
4
5  Copyright (C) 2000-2004 Jason Hunter & Brett McLaughlin.
6  All rights reserved.
7
8  Redistribution and use in source and binary forms, with or without
9  modification, are permitted provided that the following conditions
10  are met:
11
12  1. Redistributions of source code must retain the above copyright
13     notice, this list of conditions, and the following disclaimer.
14
15  2. Redistributions in binary form must reproduce the above copyright
16     notice, this list of conditions, and the disclaimer that follows
17     these conditions in the documentation and/or other materials
18     provided with the distribution.
19
20  3. The name "JDOM" must not be used to endorse or promote products
21     derived from this software without prior written permission. For
22     written permission, please contact <request_AT_jdom_DOT_org>.
23
24  4. Products derived from this software may not be called "JDOM", nor
25     may "JDOM" appear in their name, without prior written permission
26     from the JDOM Project Management <request_AT_jdom_DOT_org>.
27
28  In addition, we request (but do not require) that you include in the
29  end-user documentation provided with the redistribution and/or in the
30  software itself an acknowledgement equivalent to the following:
31      "This product includes software developed by the
32       JDOM Project (http://www.jdom.org/)."
33  Alternatively, the acknowledgment may be graphical using the logos
34  available at http://www.jdom.org/images/logos.
35
36  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
40  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  SUCH DAMAGE.
48
49  This software consists of voluntary contributions made by many
50  individuals on behalf of the JDOM Project and was originally
51  created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
52  Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
53  on the JDOM Project, please see <http://www.jdom.org/>.
54
55  */

56
57 package org.jdom;
58
59 import java.io.*;
60
61 /**
62  * An XML attribute. Methods allow the user to obtain the value of the attribute
63  * as well as namespace and type information.
64  *
65  * @version $Revision: 1.52 $, $Date: 2004/03/01 23:58:28 $
66  * @author Brett McLaughlin
67  * @author Jason Hunter
68  * @author Elliotte Rusty Harold
69  * @author Wesley Biggs
70  */

71 public class Attribute implements Serializable, Cloneable JavaDoc {
72
73     private static final String JavaDoc CVS_ID =
74       "@(#) $RCSfile: Attribute.java,v $ $Revision: 1.52 $ $Date: 2004/03/01 23:58:28 $ $Name: $";
75
76     /**
77      * Attribute type: the attribute has not been declared or type
78      * is unknown.
79      *
80      * @see #getAttributeType
81      */

82     public final static int UNDECLARED_TYPE = 0;
83
84     /**
85      * Attribute type: the attribute value is a string.
86      *
87      * @see #getAttributeType
88      */

89     public final static int CDATA_TYPE = 1;
90
91     /**
92      * Attribute type: the attribute value is a unique identifier.
93      *
94      * @see #getAttributeType
95      */

96     public final static int ID_TYPE = 2;
97
98     /**
99      * Attribute type: the attribute value is a reference to a
100      * unique identifier.
101      *
102      * @see #getAttributeType
103      */

104     public final static int IDREF_TYPE = 3;
105
106     /**
107      * Attribute type: the attribute value is a list of references to
108      * unique identifiers.
109      *
110      * @see #getAttributeType
111      */

112     public final static int IDREFS_TYPE = 4;
113
114     /**
115      * Attribute type: the attribute value is the name of an entity.
116      *
117      * @see #getAttributeType
118      */

119     public final static int ENTITY_TYPE = 5;
120
121     /**
122      * <p>
123      * Attribute type: the attribute value is a list of entity names.
124      * </p>
125      *
126      * @see #getAttributeType
127      */

128     public final static int ENTITIES_TYPE = 6;
129
130     /**
131      * Attribute type: the attribute value is a name token.
132      * <p>
133      * According to SAX 2.0 specification, attributes of enumerated
134      * types should be reported as "NMTOKEN" by SAX parsers. But the
135      * major parsers (Xerces and Crimson) provide specific values
136      * that permit to recognize them as {@link #ENUMERATED_TYPE}.
137      *
138      * @see #getAttributeType
139      */

140     public final static int NMTOKEN_TYPE = 7;
141
142     /**
143      * Attribute type: the attribute value is a list of name tokens.
144      *
145      * @see #getAttributeType
146      */

147     public final static int NMTOKENS_TYPE = 8;
148
149     /**
150      * Attribute type: the attribute value is the name of a notation.
151      *
152      * @see #getAttributeType
153      */

154     public final static int NOTATION_TYPE = 9;
155
156     /**
157      * Attribute type: the attribute value is a name token from an
158      * enumeration.
159      *
160      * @see #getAttributeType
161      */

162     public final static int ENUMERATED_TYPE = 10;
163
164     // Keep the old constant names for one beta cycle to help migration
165

166
167
168     /** The local name of the <code>Attribute</code> */
169     protected String JavaDoc name;
170
171     /** The <code>{@link Namespace}</code> of the <code>Attribute</code> */
172     protected transient Namespace namespace;
173
174     /** The value of the <code>Attribute</code> */
175     protected String JavaDoc value;
176
177     /** The type of the <code>Attribute</code> */
178     protected int type = UNDECLARED_TYPE;
179
180     /** Parent element, or null if none */
181     protected Object JavaDoc parent;
182
183     /**
184      * Default, no-args constructor for implementations to use if needed.
185      */

186     protected Attribute() {}
187
188     /**
189      * This will create a new <code>Attribute</code> with the
190      * specified (local) name and value, and in the provided
191      * <code>{@link Namespace}</code>.
192      *
193      * @param name <code>String</code> name of <code>Attribute</code>.
194      * @param value <code>String</code> value for new attribute.
195      * @param namespace <code>Namespace</code> namespace for new attribute.
196      * @throws IllegalNameException if the given name is illegal as an
197      * attribute name or if if the new namespace is the default
198      * namespace. Attributes cannot be in a default namespace.
199      * @throws IllegalDataException if the given attribute value is
200      * illegal character data (as determined by
201      * {@link org.jdom.Verifier#checkCharacterData}).
202      */

203     public Attribute(String JavaDoc name, String JavaDoc value, Namespace namespace) {
204         setName(name);
205         setValue(value);
206         setNamespace(namespace);
207     }
208
209     /**
210      * This will create a new <code>Attribute</code> with the
211      * specified (local) name, value, and type, and in the provided
212      * <code>{@link Namespace}</code>.
213      *
214      * @param name <code>String</code> name of <code>Attribute</code>.
215      * @param value <code>String</code> value for new attribute.
216      * @param type <code>int</code> type for new attribute.
217      * @param namespace <code>Namespace</code> namespace for new attribute.
218      * @throws IllegalNameException if the given name is illegal as an
219      * attribute name or if if the new namespace is the default
220      * namespace. Attributes cannot be in a default namespace.
221      * @throws IllegalDataException if the given attribute value is
222      * illegal character data (as determined by
223      * {@link org.jdom.Verifier#checkCharacterData}) or
224      * if the given attribute type is not one of the
225      * supported types.
226      */

227     public Attribute(String JavaDoc name, String JavaDoc value, int type, Namespace namespace) {
228         setName(name);
229         setValue(value);
230         setAttributeType(type);
231         setNamespace(namespace);
232     }
233
234     /**
235      * This will create a new <code>Attribute</code> with the
236      * specified (local) name and value, and does not place
237      * the attribute in a <code>{@link Namespace}</code>.
238      * <p>
239      * <b>Note</b>: This actually explicitly puts the
240      * <code>Attribute</code> in the "empty" <code>Namespace</code>
241      * (<code>{@link Namespace#NO_NAMESPACE}</code>).
242      *
243      * @param name <code>String</code> name of <code>Attribute</code>.
244      * @param value <code>String</code> value for new attribute.
245      * @throws IllegalNameException if the given name is illegal as an
246      * attribute name.
247      * @throws IllegalDataException if the given attribute value is
248      * illegal character data (as determined by
249      * {@link org.jdom.Verifier#checkCharacterData}).
250      */

251     public Attribute(String JavaDoc name, String JavaDoc value) {
252         this(name, value, UNDECLARED_TYPE, Namespace.NO_NAMESPACE);
253     }
254
255     /**
256      * This will create a new <code>Attribute</code> with the
257      * specified (local) name, value and type, and does not place
258      * the attribute in a <code>{@link Namespace}</code>.
259      * <p>
260      * <b>Note</b>: This actually explicitly puts the
261      * <code>Attribute</code> in the "empty" <code>Namespace</code>
262      * (<code>{@link Namespace#NO_NAMESPACE}</code>).
263      *
264      * @param name <code>String</code> name of <code>Attribute</code>.
265      * @param value <code>String</code> value for new attribute.
266      * @param type <code>int</code> type for new attribute.
267      * @throws IllegalNameException if the given name is illegal as an
268      * attribute name.
269      * @throws IllegalDataException if the given attribute value is
270      * illegal character data (as determined by
271      * {@link org.jdom.Verifier#checkCharacterData}) or
272      * if the given attribute type is not one of the
273      * supported types.
274      */

275     public Attribute(String JavaDoc name, String JavaDoc value, int type) {
276         this(name, value, type, Namespace.NO_NAMESPACE);
277     }
278
279     /**
280      * This will return the parent of this <code>Attribute</code>.
281      * If there is no parent, then this returns <code>null</code>.
282      *
283      * @return parent of this <code>Attribute</code>
284      */

285     public Element getParent() {
286         return (Element) parent;
287     }
288
289     /**
290      * This retrieves the owning <code>{@link Document}</code> for
291      * this Attribute, or null if not a currently a member of a
292      * <code>{@link Document}</code>.
293      *
294      * @return <code>Document</code> owning this Attribute, or null.
295      */

296     public Document getDocument() {
297         if (parent != null) {
298             return ((Element)parent).getDocument();
299         }
300         return null;
301     }
302
303     /**
304      * This will set the parent of this <code>Attribute</code>.
305      *
306      * @param parent <code>Element</code> to be new parent.
307      * @return this <code>Attribute</code> modified.
308      */

309     protected Attribute setParent(Element parent) {
310         this.parent = parent;
311         return this;
312     }
313
314     /**
315      * This detaches the <code>Attribute</code> from its parent, or does
316      * nothing if the <code>Attribute</code> has no parent.
317      *
318      * @return <code>Attribute</code> - this <code>Attribute</code> modified.
319      */

320     public Attribute detach() {
321         Element p = getParent();
322         if (p != null) {
323             p.removeAttribute(this.getName(), this.getNamespace());
324         }
325         return this;
326     }
327
328     /**
329      * This will retrieve the local name of the
330      * <code>Attribute</code>. For any XML attribute
331      * which appears as
332      * <code>[namespacePrefix]:[attributeName]</code>,
333      * the local name of the attribute would be
334      * <code>[attributeName]</code>. When the attribute
335      * has no namespace, the local name is simply the attribute
336      * name.
337      * <p>
338      * To obtain the namespace prefix for this
339      * attribute, the
340      * <code>{@link #getNamespacePrefix()}</code>
341      * method should be used.
342      *
343      * @return <code>String</code> - name of this attribute,
344      * without any namespace prefix.
345      */

346     public String JavaDoc getName() {
347         return name;
348     }
349
350     /**
351      * This sets the local name of the <code>Attribute</code>.
352      *
353      * @param name the new local name to set
354      * @return <code>Attribute</code> - the attribute modified.
355      * @throws IllegalNameException if the given name is illegal as an
356      * attribute name.
357      */

358     public Attribute setName(String JavaDoc name) {
359         String JavaDoc reason;
360         if ((reason = Verifier.checkAttributeName(name)) != null) {
361             throw new IllegalNameException(name, "attribute", reason);
362         }
363         this.name = name;
364         return this;
365     }
366
367     /**
368      * This will retrieve the qualified name of the <code>Attribute</code>.
369      * For any XML attribute whose name is
370      * <code>[namespacePrefix]:[elementName]</code>,
371      * the qualified name of the attribute would be
372      * everything (both namespace prefix and
373      * element name). When the attribute has no
374      * namespace, the qualified name is simply the attribute's
375      * local name.
376      * <p>
377      * To obtain the local name of the attribute, the
378      * <code>{@link #getName()}</code> method should be used.
379      * <p>
380      * To obtain the namespace prefix for this attribute,
381      * the <code>{@link #getNamespacePrefix()}</code>
382      * method should be used.
383      *
384      * @return <code>String</code> - full name for this element.
385      */

386     public String JavaDoc getQualifiedName() {
387         // Note: Any changes here should be reflected in
388
// XMLOutputter.printQualifiedName()
389
String JavaDoc prefix = namespace.getPrefix();
390         if ((prefix != null) && (!prefix.equals(""))) {
391             return new StringBuffer JavaDoc(prefix)
392                 .append(':')
393                 .append(getName())
394                 .toString();
395         } else {
396             return getName();
397         }
398     }
399
400     /**
401      * This will retrieve the namespace prefix of the
402      * <code>Attribute</code>. For any XML attribute
403      * which appears as
404      * <code>[namespacePrefix]:[attributeName]</code>,
405      * the namespace prefix of the attribute would be
406      * <code>[namespacePrefix]</code>. When the attribute
407      * has no namespace, an empty <code>String</code> is returned.
408      *
409      * @return <code>String</code> - namespace prefix of this
410      * attribute.
411      */

412     public String JavaDoc getNamespacePrefix() {
413         return namespace.getPrefix();
414     }
415
416     /**
417      * This returns the URI mapped to this <code>Attribute</code>'s
418      * prefix. If no mapping is found, an empty <code>String</code> is
419      * returned.
420      *
421      * @return <code>String</code> - namespace URI for this <code>Attribute</code>.
422      */

423     public String JavaDoc getNamespaceURI() {
424         return namespace.getURI();
425     }
426
427     /**
428      * This will return this <code>Attribute</code>'s
429      * <code>{@link Namespace}</code>.
430      *
431      * @return <code>Namespace</code> - Namespace object for this <code>Attribute</code>
432      */

433     public Namespace getNamespace() {
434         return namespace;
435     }
436
437     /**
438      * This sets this <code>Attribute</code>'s <code>{@link Namespace}</code>.
439      * If the provided namespace is null, the attribute will have no namespace.
440      * The namespace must have a prefix.
441      *
442      * @param namespace the new namespace
443      * @return <code>Element</code> - the element modified.
444      * @throws IllegalNameException if the new namespace is the default
445      * namespace. Attributes cannot be in a default namespace.
446      */

447     public Attribute setNamespace(Namespace namespace) {
448         if (namespace == null) {
449             namespace = Namespace.NO_NAMESPACE;
450         }
451
452         // Verify the attribute isn't trying to be in a default namespace
453
// Attributes can't be in a default namespace
454
if (namespace != Namespace.NO_NAMESPACE &&
455             namespace.getPrefix().equals("")) {
456             throw new IllegalNameException("", "attribute namespace",
457                 "An attribute namespace without a prefix can only be the " +
458                 "NO_NAMESPACE namespace");
459         }
460         this.namespace = namespace;
461         return this;
462     }
463     /**
464      * This will return the actual textual value of this
465      * <code>Attribute</code>. This will include all text
466      * within the quotation marks.
467      *
468      * @return <code>String</code> - value for this attribute.
469      */

470     public String JavaDoc getValue() {
471         return value;
472     }
473
474     /**
475      * This will set the value of the <code>Attribute</code>.
476      *
477      * @param value <code>String</code> value for the attribute.
478      * @return <code>Attribute</code> - this Attribute modified.
479      * @throws IllegalDataException if the given attribute value is
480      * illegal character data (as determined by
481      * {@link org.jdom.Verifier#checkCharacterData}).
482      */

483     public Attribute setValue(String JavaDoc value) {
484         String JavaDoc reason = null;
485         if ((reason = Verifier.checkCharacterData(value)) != null) {
486             throw new IllegalDataException(value, "attribute", reason);
487         }
488         this.value = value;
489         return this;
490     }
491
492     /**
493      * This will return the actual declared type of this
494      * <code>Attribute</code>.
495      *
496      * @return <code>int</code> - type for this attribute.
497      */

498     public int getAttributeType() {
499         return type;
500     }
501
502     /**
503      * This will set the type of the <code>Attribute</code>.
504      *
505      * @param type <code>int</code> type for the attribute.
506      * @return <code>Attribute</code> - this Attribute modified.
507      * @throws IllegalDataException if the given attribute type is
508      * not one of the supported types.
509      */

510     public Attribute setAttributeType(int type) {
511         if ((type < UNDECLARED_TYPE) || (type > ENUMERATED_TYPE)) {
512             throw new IllegalDataException(String.valueOf(type),
513                                         "attribute", "Illegal attribute type");
514         }
515         this.type = type;
516         return this;
517     }
518
519     /**
520      * This returns a <code>String</code> representation of the
521      * <code>Attribute</code>, suitable for debugging.
522      *
523      * @return <code>String</code> - information about the
524      * <code>Attribute</code>
525      */

526     public String JavaDoc toString() {
527         return new StringBuffer JavaDoc()
528             .append("[Attribute: ")
529             .append(getQualifiedName())
530             .append("=\"")
531             .append(value)
532             .append("\"")
533             .append("]")
534             .toString();
535     }
536
537     /**
538      * This tests for equality of this <code>Attribute</code> to the supplied
539      * <code>Object</code>.
540      *
541      * @param ob <code>Object</code> to compare to.
542      * @return <code>boolean</code> - whether the <code>Attribute</code> is
543      * equal to the supplied <code>Object</code>.
544      */

545     public final boolean equals(Object JavaDoc ob) {
546         return (ob == this);
547     }
548
549     /**
550      * This returns the hash code for this <code>Attribute</code>.
551      *
552      * @return <code>int</code> - hash code.
553      */

554     public final int hashCode() {
555         return super.hashCode();
556     }
557
558     /**
559      * This will return a clone of this <code>Attribute</code>.
560      *
561      * @return <code>Object</code> - clone of this <code>Attribute</code>.
562      */

563     public Object JavaDoc clone() {
564         Attribute attribute = null;
565
566         try {
567             attribute = (Attribute) super.clone();
568         } catch(CloneNotSupportedException JavaDoc ce) {
569             // Won't happen
570
}
571
572         // Name, namespace, and value are references to imutable objects
573
// and are copied by super.clone() (aka Object.clone())
574

575         // super.clone() copies reference to set parent to null
576
attribute.parent = null;
577         return attribute;
578     }
579
580     /////////////////////////////////////////////////////////////////
581
// Convenience Methods below here
582
/////////////////////////////////////////////////////////////////
583

584     /**
585      * This gets the value of the attribute, in
586      * <code>int</code> form, and if no conversion
587      * can occur, throws a
588      * <code>{@link DataConversionException}</code>
589      *
590      * @return <code>int</code> value of attribute.
591      * @throws DataConversionException when conversion fails.
592      */

593     public int getIntValue() throws DataConversionException {
594         try {
595             return Integer.parseInt(value.trim());
596         } catch (NumberFormatException JavaDoc e) {
597             throw new DataConversionException(name, "int");
598         }
599     }
600
601     /**
602      * This gets the value of the attribute, in
603      * <code>long</code> form, and if no conversion
604      * can occur, throws a
605      * <code>{@link DataConversionException}</code>
606      *
607      * @return <code>long</code> value of attribute.
608      * @throws DataConversionException when conversion fails.
609      */

610     public long getLongValue() throws DataConversionException {
611         try {
612             return Long.parseLong(value.trim());
613         } catch (NumberFormatException JavaDoc e) {
614             throw new DataConversionException(name, "long");
615         }
616     }
617
618     /**
619      * This gets the value of the attribute, in
620      * <code>float</code> form, and if no conversion
621      * can occur, throws a
622      * <code>{@link DataConversionException}</code>
623      *
624      * @return <code>float</code> value of attribute.
625      * @throws DataConversionException when conversion fails.
626      */

627     public float getFloatValue() throws DataConversionException {
628         try {
629             // Avoid Float.parseFloat() to support JDK 1.1
630
return Float.valueOf(value.trim()).floatValue();
631         } catch (NumberFormatException JavaDoc e) {
632             throw new DataConversionException(name, "float");
633         }
634     }
635
636     /**
637      * This gets the value of the attribute, in
638      * <code>double</code> form, and if no conversion
639      * can occur, throws a
640      * <code>{@link DataConversionException}</code>
641      *
642      * @return <code>double</code> value of attribute.
643      * @throws DataConversionException when conversion fails.
644      */

645     public double getDoubleValue() throws DataConversionException {
646         try {
647             // Avoid Double.parseDouble() to support JDK 1.1
648
return Double.valueOf(value.trim()).doubleValue();
649         } catch (NumberFormatException JavaDoc e) {
650             throw new DataConversionException(name, "double");
651         }
652     }
653
654     /**
655      * This gets the effective boolean value of the attribute, or throws a
656      * <code>{@link DataConversionException}</code> if a conversion can't be
657      * performed. True values are: "true", "on", "1", and "yes". False
658      * values are: "false", "off", "0", and "no". Values are trimmed before
659      * comparison. Values other than those listed here throw the exception.
660      *
661      * @return <code>boolean</code> value of attribute.
662      * @throws DataConversionException when conversion fails.
663      */

664     public boolean getBooleanValue() throws DataConversionException {
665         String JavaDoc valueTrim = value.trim();
666         if ((valueTrim.equalsIgnoreCase("true")) ||
667             (valueTrim.equalsIgnoreCase("on")) ||
668             (valueTrim.equalsIgnoreCase("1")) ||
669             (valueTrim.equalsIgnoreCase("yes"))) {
670             return true;
671         } else if ((valueTrim.equalsIgnoreCase("false")) ||
672                    (valueTrim.equalsIgnoreCase("off")) ||
673                    (valueTrim.equalsIgnoreCase("0")) ||
674                    (valueTrim.equalsIgnoreCase("no"))) {
675             return false;
676         } else {
677             throw new DataConversionException(name, "boolean");
678         }
679     }
680
681     // Support a custom Namespace serialization so no two namespace
682
// object instances may exist for the same prefix/uri pair
683
private void writeObject(ObjectOutputStream out) throws IOException {
684
685         out.defaultWriteObject();
686
687         // We use writeObject() and not writeUTF() to minimize space
688
// This allows for writing pointers to already written strings
689
out.writeObject(namespace.getPrefix());
690         out.writeObject(namespace.getURI());
691     }
692
693     private void readObject(ObjectInputStream in)
694         throws IOException, ClassNotFoundException JavaDoc {
695
696         in.defaultReadObject();
697
698         namespace = Namespace.getNamespace(
699             (String JavaDoc)in.readObject(), (String JavaDoc)in.readObject());
700     }
701 }
702
Popular Tags