org.jdom2.Attribute Maven / Gradle / Ivy
Show all versions of jdom Show documentation
/*--
Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions, and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions, and the disclaimer that follows
these conditions in the documentation and/or other materials
provided with the distribution.
3. The name "JDOM" must not be used to endorse or promote products
derived from this software without prior written permission. For
written permission, please contact .
4. Products derived from this software may not be called "JDOM", nor
may "JDOM" appear in their name, without prior written permission
from the JDOM Project Management .
In addition, we request (but do not require) that you include in the
end-user documentation provided with the redistribution and/or in the
software itself an acknowledgement equivalent to the following:
"This product includes software developed by the
JDOM Project (http://www.jdom.org/)."
Alternatively, the acknowledgment may be graphical using the logos
available at http://www.jdom.org/images/logos.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
This software consists of voluntary contributions made by many
individuals on behalf of the JDOM Project and was originally
created by Jason Hunter and
Brett McLaughlin . For more information
on the JDOM Project, please see .
*/
package org.jdom2;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.TreeMap;
/**
* An XML attribute. Methods allow the user to obtain the value of the attribute
* as well as namespace and type information.
*
* JDOM 1.x Compatibility Note:
* The Attribute class in JDOM 1.x had a number of int Constants declared to
* represent different Attribute Types. JDOM2 has introduced an AttributeType
* enumeration instead. To facilitate compatibility and to simplify JDOM 1.x
* migrations, the replacement AttributeType enums are referenced still using
* the JDOM 1.x constant names. In JDOM 1.x these names referenced constant
* int values. In JDOM2 these names reference Enum constants.
*
* @author Brett McLaughlin
* @author Jason Hunter
* @author Elliotte Rusty Harold
* @author Wesley Biggs
* @author Victor Toni
* @author Rolf Lear
*/
public class Attribute extends CloneBase
implements NamespaceAware, Serializable, Cloneable {
/**
* JDOM 2.0.0 Serialization version. Attribute is simple
*/
private static final long serialVersionUID = 200L;
// Keep the old constant names for one beta cycle to help migration
/** JDOM 1.x compatible reference to {@link AttributeType#UNDECLARED} */
public final static AttributeType UNDECLARED_TYPE = AttributeType.UNDECLARED;
/** JDOM 1.x compatible reference to {@link AttributeType#CDATA} */
public final static AttributeType CDATA_TYPE = AttributeType.CDATA;
/** JDOM 1.x compatible reference to {@link AttributeType#ID} */
public final static AttributeType ID_TYPE = AttributeType.ID;
/** JDOM 1.x compatible reference to {@link AttributeType#IDREF} */
public final static AttributeType IDREF_TYPE = AttributeType.IDREF;
/** JDOM 1.x compatible reference to {@link AttributeType#IDREFS} */
public final static AttributeType IDREFS_TYPE = AttributeType.IDREFS;
/** JDOM 1.x compatible reference to {@link AttributeType#ENTITY} */
public final static AttributeType ENTITY_TYPE = AttributeType.ENTITY;
/** JDOM 1.x compatible reference to {@link AttributeType#ENTITIES} */
public final static AttributeType ENTITIES_TYPE = AttributeType.ENTITIES;
/** JDOM 1.x compatible reference to {@link AttributeType#NMTOKEN} */
public final static AttributeType NMTOKEN_TYPE = AttributeType.NMTOKEN;
/** JDOM 1.x compatible reference to {@link AttributeType#NMTOKENS} */
public final static AttributeType NMTOKENS_TYPE = AttributeType.NMTOKENS;
/** JDOM 1.x compatible reference to {@link AttributeType#NOTATION} */
public final static AttributeType NOTATION_TYPE = AttributeType.NOTATION;
/** JDOM 1.x compatible reference to {@link AttributeType#ENUMERATION} */
public final static AttributeType ENUMERATED_TYPE = AttributeType.ENUMERATION;
/** The local name of the Attribute
*/
protected String name;
/** The {@link Namespace}
of the Attribute
*/
protected Namespace namespace;
/** The value of the Attribute
*/
protected String value;
/** The type of the Attribute
*/
protected AttributeType type = AttributeType.UNDECLARED;
/**
* Specified attributes are part of the XML,
* unspecified attributes are 'defaulted' from a DTD.
*/
protected boolean specified = true;
/**
* The parent to which this Attribute belongs. Change it with
* {@link #setParent(Element)}
*/
protected transient Element parent;
/**
* Default, no-args constructor for implementations to use if needed.
*/
protected Attribute() {
}
/**
* This will create a new Attribute
with the
* specified (local) name and value, and in the provided
* {@link Namespace}
.
*
* @param name String
name of Attribute
.
* @param value String
value for new attribute.
* @param namespace Namespace
namespace for new attribute.
* @throws IllegalNameException if the given name is illegal as an
* attribute name or if if the new namespace is the default
* namespace. Attributes cannot be in a default namespace.
* @throws IllegalDataException if the given attribute value is
* illegal character data (as determined by
* {@link org.jdom2.Verifier#checkCharacterData}).
*/
public Attribute(final String name, final String value, final Namespace namespace) {
this(name, value, AttributeType.UNDECLARED, namespace);
}
/**
* This will create a new Attribute
with the
* specified (local) name, value, and type, and in the provided
* {@link Namespace}
.
*
* @param name String
name of Attribute
.
* @param value String
value for new attribute.
* @param type int
type for new attribute.
* @param namespace Namespace
namespace for new attribute.
* @throws IllegalNameException if the given name is illegal as an
* attribute name or if if the new namespace is the default
* namespace. Attributes cannot be in a default namespace.
* @throws IllegalDataException if the given attribute value is
* illegal character data (as determined by
* {@link org.jdom2.Verifier#checkCharacterData}) or
* if the given attribute type is not one of the
* supported types.
* @deprecated Use {@link #Attribute(String, String, AttributeType, Namespace)}.
*/
@Deprecated
public Attribute(final String name, final String value, final int type, final Namespace namespace) {
this(name, value, AttributeType.byIndex(type), namespace);
}
/**
* This will create a new Attribute
with the
* specified (local) name, value, and type, and in the provided
* {@link Namespace}
.
*
* @param name String
name of Attribute
.
* @param value String
value for new attribute.
* @param type AttributeType
for new attribute.
* @param namespace Namespace
namespace for new attribute.
* @throws IllegalNameException if the given name is illegal as an
* attribute name or if if the new namespace is the default
* namespace. Attributes cannot be in a default namespace.
* @throws IllegalDataException if the given attribute value is
* illegal character data (as determined by
* {@link org.jdom2.Verifier#checkCharacterData}) or
* if the given attribute type is not one of the
* supported types.
*/
public Attribute(final String name, final String value, final AttributeType type, final Namespace namespace) {
setName(name);
setValue(value);
setAttributeType(type);
setNamespace(namespace);
}
/**
* This will create a new Attribute
with the
* specified (local) name and value, and does not place
* the attribute in a {@link Namespace}
.
*
* Note: This actually explicitly puts the
* Attribute
in the "empty" Namespace
* ({@link Namespace#NO_NAMESPACE}
).
*
* @param name String
name of Attribute
.
* @param value String
value for new attribute.
* @throws IllegalNameException if the given name is illegal as an
* attribute name.
* @throws IllegalDataException if the given attribute value is
* illegal character data (as determined by
* {@link org.jdom2.Verifier#checkCharacterData}).
*/
public Attribute(final String name, final String value) {
this(name, value, AttributeType.UNDECLARED, Namespace.NO_NAMESPACE);
}
/**
* This will create a new Attribute
with the
* specified (local) name, value and type, and does not place
* the attribute in a {@link Namespace}
.
*
* Note: This actually explicitly puts the
* Attribute
in the "empty" Namespace
* ({@link Namespace#NO_NAMESPACE}
).
*
* @param name String
name of Attribute
.
* @param value String
value for new attribute.
* @param type AttributeType
for new attribute.
* @throws IllegalNameException if the given name is illegal as an
* attribute name.
* @throws IllegalDataException if the given attribute value is
* illegal character data (as determined by
* {@link org.jdom2.Verifier#checkCharacterData}) or
* if the given attribute type is not one of the
* supported types.
*/
public Attribute(final String name, final String value, final AttributeType type) {
this(name, value, type, Namespace.NO_NAMESPACE);
}
/**
* This will create a new Attribute
with the
* specified (local) name, value and type, and does not place
* the attribute in a {@link Namespace}
.
*
* Note: This actually explicitly puts the
* Attribute
in the "empty" Namespace
* ({@link Namespace#NO_NAMESPACE}
).
*
* @param name String
name of Attribute
.
* @param value String
value for new attribute.
* @param type int
type for new attribute.
* @throws IllegalNameException if the given name is illegal as an
* attribute name.
* @throws IllegalDataException if the given attribute value is
* illegal character data (as determined by
* {@link org.jdom2.Verifier#checkCharacterData}) or
* if the given attribute type is not one of the
* supported types.
* @deprecated Use {@link #Attribute(String, String, AttributeType)}
*/
@Deprecated
public Attribute(final String name, final String value, final int type) {
this(name, value, type, Namespace.NO_NAMESPACE);
}
/**
* This will return the parent of this Attribute
.
* If there is no parent, then this returns null
.
* Use return-type covariance to override Content's getParent() method
* to return an Element, not just a Parent
*
* @return parent of this Attribute
*/
public Element getParent() {
return parent;
}
/**
* Get this Attribute's Document.
* @return The document to which this Attribute is associated, may be null.
*/
public Document getDocument() {
return parent == null ? null : parent.getDocument();
}
/**
* This will retrieve the local name of the
* Attribute
. For any XML attribute
* which appears as
* [namespacePrefix]:[attributeName]
,
* the local name of the attribute would be
* [attributeName]
. When the attribute
* has no namespace, the local name is simply the attribute
* name.
*
* To obtain the namespace prefix for this
* attribute, the
* {@link #getNamespacePrefix()}
* method should be used.
*
* @return String
- name of this attribute,
* without any namespace prefix.
*/
public String getName() {
return name;
}
/**
* This sets the local name of the Attribute
.
*
* @param name the new local name to set
* @return Attribute
- the attribute modified.
* @throws IllegalNameException if the given name is illegal as an
* attribute name.
*/
public Attribute setName(final String name) {
if (name == null) {
throw new NullPointerException(
"Can not set a null name for an Attribute.");
}
final String reason = Verifier.checkAttributeName(name);
if (reason != null) {
throw new IllegalNameException(name, "attribute", reason);
}
this.name = name;
specified = true;
return this;
}
/**
* This will retrieve the qualified name of the Attribute
.
* For any XML attribute whose name is
* [namespacePrefix]:[elementName]
,
* the qualified name of the attribute would be
* everything (both namespace prefix and
* element name). When the attribute has no
* namespace, the qualified name is simply the attribute's
* local name.
*
* To obtain the local name of the attribute, the
* {@link #getName()}
method should be used.
*
* To obtain the namespace prefix for this attribute,
* the {@link #getNamespacePrefix()}
* method should be used.
*
* @return String
- full name for this element.
*/
public String getQualifiedName() {
// Note: Any changes here should be reflected in
// XMLOutputter.printQualifiedName()
final String prefix = namespace.getPrefix();
// no prefix found
if ("".equals(prefix)) {
return getName();
}
return new StringBuilder(prefix)
.append(':')
.append(getName())
.toString();
}
/**
* This will retrieve the namespace prefix of the
* Attribute
. For any XML attribute
* which appears as
* [namespacePrefix]:[attributeName]
,
* the namespace prefix of the attribute would be
* [namespacePrefix]
. When the attribute
* has no namespace, an empty String
is returned.
*
* @return String
- namespace prefix of this
* attribute.
*/
public String getNamespacePrefix() {
return namespace.getPrefix();
}
/**
* This returns the URI mapped to this Attribute
's
* prefix. If no mapping is found, an empty String
is
* returned.
*
* @return String
- namespace URI for this Attribute
.
*/
public String getNamespaceURI() {
return namespace.getURI();
}
/**
* This will return this Attribute
's
* {@link Namespace}
.
*
* @return Namespace
- Namespace object for this Attribute
*/
public Namespace getNamespace() {
return namespace;
}
/**
* This sets this Attribute
's {@link Namespace}
.
* If the provided namespace is null, the attribute will have no namespace.
* The namespace must have a prefix.
*
* @param namespace the new namespace
* @return Element
- the element modified.
* @throws IllegalNameException if the new namespace is the default
* namespace. Attributes cannot be in a default namespace.
*/
public Attribute setNamespace(Namespace namespace) {
if (namespace == null) {
namespace = Namespace.NO_NAMESPACE;
}
// Verify the attribute isn't trying to be in a default namespace
// Attributes can't be in a default namespace
if (namespace != Namespace.NO_NAMESPACE &&
"".equals(namespace.getPrefix())) {
throw new IllegalNameException("", "attribute namespace",
"An attribute namespace without a prefix can only be the " +
"NO_NAMESPACE namespace");
}
this.namespace = namespace;
specified = true;
return this;
}
/**
* This will return the actual textual value of this
* Attribute
. This will include all text
* within the quotation marks.
*
* @return String
- value for this attribute.
*/
public String getValue() {
return value;
}
/**
* This will set the value of the Attribute
.
*
* @param value String
value for the attribute.
* @return Attribute
- this Attribute modified.
* @throws IllegalDataException if the given attribute value is
* illegal character data (as determined by
* {@link org.jdom2.Verifier#checkCharacterData}).
*/
public Attribute setValue(final String value) {
if (value == null) {
throw new NullPointerException(
"Can not set a null value for an Attribute");
}
final String reason = Verifier.checkCharacterData(value);
if (reason != null) {
throw new IllegalDataException(value, "attribute", reason);
}
this.value = value;
specified = true;
return this;
}
/**
* This will return the declared type of this Attribute
.
*
* @return AttributeType
- type for this attribute.
*/
public AttributeType getAttributeType() {
return type;
}
/**
* This will set the type of the Attribute
.
*
* @param type int
type for the attribute.
* @return Attribute
- this Attribute modified.
* @throws IllegalDataException if the given attribute type is
* not one of the supported types.
*/
public Attribute setAttributeType(final AttributeType type) {
this.type = type == null ? AttributeType.UNDECLARED : type;
specified = true;
return this;
}
/**
* This will set the type of the Attribute
.
*
* @param type int
type for the attribute.
* @return Attribute
- this Attribute modified.
* @throws IllegalDataException if the given attribute type is
* not one of the supported types.
* @deprecated use {@link #setAttributeType(AttributeType)}
*/
@Deprecated
public Attribute setAttributeType(final int type) {
setAttributeType(AttributeType.byIndex(type));
return this;
}
/**
* Get the 'specified' flag. True values indicate this attribute
* was part of an XML document, false indicates it was defaulted
* from a DTD.
* @return the specified flag.
* @since JDOM2
*/
public boolean isSpecified() {
return specified;
}
/**
* Change the specified flag to the given value.
* @param specified The value to set the specified flag to.
* @since JDOM2
*/
public void setSpecified(boolean specified) {
this.specified = specified;
}
/**
* This returns a String
representation of the
* Attribute
, suitable for debugging.
*
* @return String
- information about the
* Attribute
*/
@Override
public String toString() {
return new StringBuilder()
.append("[Attribute: ")
.append(getQualifiedName())
.append("=\"")
.append(value)
.append("\"")
.append("]")
.toString();
}
@Override
public Attribute clone() {
final Attribute clone = (Attribute) super.clone();
clone.parent = null;
return clone;
}
/**
* Detach this Attribute from its parent.
* @return this Attribute (detached).
*/
public Attribute detach() {
if (parent != null) {
parent.removeAttribute(this);
}
return this;
}
/**
* Set this Attribute's parent. This is not public!
* @param parent The parent to set
* @return this Attribute (state may be indeterminate depending on whether
* this has been included in the Element's list yet).
*/
protected Attribute setParent(Element parent) {
this.parent = parent;
return this;
}
/////////////////////////////////////////////////////////////////
// Convenience Methods below here
/////////////////////////////////////////////////////////////////
/**
* This gets the value of the attribute, in
* int
form, and if no conversion
* can occur, throws a
* {@link DataConversionException}
*
* @return int
value of attribute.
* @throws DataConversionException when conversion fails.
*/
public int getIntValue() throws DataConversionException {
try {
return Integer.parseInt(value.trim());
} catch (final NumberFormatException e) {
throw new DataConversionException(name, "int");
}
}
/**
* This gets the value of the attribute, in
* long
form, and if no conversion
* can occur, throws a
* {@link DataConversionException}
*
* @return long
value of attribute.
* @throws DataConversionException when conversion fails.
*/
public long getLongValue() throws DataConversionException {
try {
return Long.parseLong(value.trim());
} catch (final NumberFormatException e) {
throw new DataConversionException(name, "long");
}
}
/**
* This gets the value of the attribute, in
* float
form, and if no conversion
* can occur, throws a
* {@link DataConversionException}
*
* @return float
value of attribute.
* @throws DataConversionException when conversion fails.
*/
public float getFloatValue() throws DataConversionException {
try {
// Avoid Float.parseFloat() to support JDK 1.1
return Float.valueOf(value.trim()).floatValue();
} catch (final NumberFormatException e) {
throw new DataConversionException(name, "float");
}
}
/**
* This gets the value of the attribute, in
* double
form, and if no conversion
* can occur, throws a
* {@link DataConversionException}
*
* @return double
value of attribute.
* @throws DataConversionException when conversion fails.
*/
public double getDoubleValue() throws DataConversionException {
try {
// Avoid Double.parseDouble() to support JDK 1.1
return Double.valueOf(value.trim()).doubleValue();
} catch (final NumberFormatException e) {
// Specially handle INF and -INF that Double.valueOf doesn't do
String v = value.trim();
if ("INF".equals(v)) {
return Double.POSITIVE_INFINITY;
}
if ("-INF".equals(v)) {
return Double.NEGATIVE_INFINITY;
}
throw new DataConversionException(name, "double");
}
}
/**
* This gets the effective boolean value of the attribute, or throws a
* {@link DataConversionException}
if a conversion can't be
* performed. True values are: "true", "on", "1", and "yes". False
* values are: "false", "off", "0", and "no". Values are trimmed before
* comparison. Values other than those listed here throw the exception.
*
* @return boolean
value of attribute.
* @throws DataConversionException when conversion fails.
*/
public boolean getBooleanValue() throws DataConversionException {
final String valueTrim = value.trim();
if (
(valueTrim.equalsIgnoreCase("true")) ||
(valueTrim.equalsIgnoreCase("on")) ||
(valueTrim.equalsIgnoreCase("1")) ||
(valueTrim.equalsIgnoreCase("yes"))) {
return true;
} else if (
(valueTrim.equalsIgnoreCase("false")) ||
(valueTrim.equalsIgnoreCase("off")) ||
(valueTrim.equalsIgnoreCase("0")) ||
(valueTrim.equalsIgnoreCase("no"))
) {
return false;
} else {
throw new DataConversionException(name, "boolean");
}
}
/**
* Get the namespaces that are in-scope on this Attribute.
*
* Attribute has peculiarities that affect the in-scope Namespaces because
* there are conditions in which the Attribute's scope is different to its
* parent Element's scope. Specifically, if the parent Element is in a
* 'default' Namespace that is not the empty Namespace (e.g.
* xmlns="someurl") and this Attribute is also in the default Namespace (has
* no prefix - but for Attributes that means the Namespace URL is ""), then
* this Attribute has a different namespace scope from it's parent Element
* because it does not include the 'someurl' Namespace.
*
* In the above conditions (no-prefix Attribute in an Element with a
* non-empty no-prefix Namespace) this Attribute effectively re-binds the ""
* prefix to the "" URL, thus the Attribute 'introduces' the Namespace.
* It follows then that the getNamespacesIntroduced() will return a list
* with the single member {@link Namespace#NO_NAMESPACE}.
*
* Note that the Attribute's Namespace will always be reported first.
*
* Description copied from
* {@link NamespaceAware#getNamespacesInScope()}:
*
* {@inheritDoc}
*/
@Override
public List getNamespacesInScope() {
if (getParent() == null) {
ArrayList ret = new ArrayList(3);
ret.add(getNamespace());
ret.add(Namespace.XML_NAMESPACE);
return Collections.unmodifiableList(ret);
}
return orderFirst(getNamespace(), getParent().getNamespacesInScope());
}
@Override
public List getNamespacesIntroduced() {
if (getParent() == null) {
return Collections.singletonList(getNamespace());
}
return Collections.emptyList();
}
@Override
public List getNamespacesInherited() {
if (getParent() == null) {
return Collections.singletonList(Namespace.XML_NAMESPACE);
}
return orderFirst(getNamespace(), getParent().getNamespacesInScope());
}
private static final List orderFirst(final Namespace nsa,
final List nsl) {
if (nsl.get(0) == nsa) {
return nsl;
}
// OK, we have our namespace list, but our's is not the first.
// we need the Attribute's Namespace to be up front.
TreeMap tm = new TreeMap();
for (Namespace ns : nsl) {
if (ns != nsa) {
tm.put(ns.getPrefix(), ns);
}
}
ArrayList ret = new ArrayList(tm.size() + 1);
ret.add(nsa);
ret.addAll(tm.values());
return Collections.unmodifiableList(ret);
}
}