/*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.ukit.dom;
import org.w3c.dom.Node;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.Document;
import org.w3c.dom.DOMException;
/**
* DOM attribute node implementation.
*
* @see org.w3c.dom.Node
*/
/* pkg */ final class AttrImp
extends XParent
implements Attr
{
/** Attribute value. */
private String value;
/**
* Constructs attribute object from other attribute.
*/
/* pkg */ AttrImp(AttrImp attr, boolean deep)
{
super(attr, true);
value = attr.value;
}
/**
* Constructs attribute object from its qualified name and namespace URI
* and its owner document.
*/
/* pkg */ AttrImp(String namespaceURI, String qName, XDoc ownerDocument)
{
super(namespaceURI, qName, ownerDocument);
value = "";
}
/**
* A code representing the type of the underlying object, as defined above.
*/
public short getNodeType()
{
return ATTRIBUTE_NODE;
}
/**
* The parent of this node. All nodes, except <code>Attr</code>,
* <code>Document</code>, <code>DocumentFragment</code>,
* <code>Entity</code>, and <code>Notation</code> may have a parent.
* However, if a node has just been created and not yet added to the
* tree, or if it has been removed from the tree, this is
* <code>null</code>.
*/
public Node getParentNode()
{
return null;
}
/**
* Returns the name of this attribute.
*/
public String getName()
{
return getNodeName();
}
/**
* Sets the namespace prefix of this node.
* <br>Note that setting this attribute, when permitted, changes the
* <code>nodeName</code> attribute, which holds the qualified name, as
* well as the <code>tagName</code> and <code>name</code> attributes of
* the <code>Element</code> and <code>Attr</code> interfaces, when
* applicable.
* <br>Note also that changing the prefix of an attribute that is known to
* have a default value, does not make a new attribute with the default
* value and the original prefix appear, since the
* <code>namespaceURI</code> and <code>localName</code> do not change.
*
* @param prefix This node namespace prefix.
* @exception DOMException
* INVALID_CHARACTER_ERR: Raised if the specified prefix contains an
* illegal character.
* <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
* <br>NAMESPACE_ERR: Raised if the specified <code>prefix</code> is
* malformed, if the <code>namespaceURI</code> of this node is
* <code>null</code>, if the specified prefix is "xml" and the
* <code>namespaceURI</code> of this node is different from "
* http://www.w3.org/XML/1998/namespace", if this node is an attribute
* and the specified prefix is "xmlns" and the
* <code>namespaceURI</code> of this node is different from "
* http://www.w3.org/2000/xmlns/", or if this node is an attribute and
* the <code>qualifiedName</code> of this node is "xmlns" .
* @since DOM Level 2
*/
public void setPrefix(String prefix)
throws DOMException
{
if (_isNS() == false)
return; // created with non-NS methods have null prefix
XElm elm = (XElm)_getParent();
if (elm != null) {
int idx = elm._getAttrIdx(this);
if (elm._isDefAttr(idx)) // preserve default attributes qname
return;
_setPrefix(prefix);
elm.__setAttrQN(idx, getNodeName());
} else {
_setPrefix(prefix);
}
}
/**
* If this attribute was explicitly given a value in the original
* document, this is <code>true</code>; otherwise, it is
* <code>false</code>. Note that the implementation is in charge of this
* attribute, not the user. If the user changes the value of the
* attribute (even if it ends up having the same value as the default
* value) then the <code>specified</code> flag is automatically flipped
* to <code>true</code>. To re-specify the attribute as the default
* value from the DTD, the user must delete the attribute. The
* implementation will then make a new attribute available with
* <code>specified</code> set to <code>false</code> and the default
* value (if one exists).
* <br>In summary: If the attribute has an assigned value in the document
* then <code>specified</code> is <code>true</code>, and the value is
* the assigned value. If the attribute has no assigned value in the
* document and has a default value in the DTD, then
* <code>specified</code> is <code>false</code>, and the value is the
* default value in the DTD. If the attribute has no assigned value in
* the document and has a value of #IMPLIED in the DTD, then the
* attribute does not appear in the structure model of the document. If
* the <code>ownerElement</code> attribute is <code>null</code> (i.e.
* because it was just created or was set to <code>null</code> by the
* various removal and cloning operations) <code>specified</code> is
* <code>true</code>.
*/
public boolean getSpecified()
{
XElm elm = (XElm)_getParent();
if (elm == null)
return true;
int idx = elm._getAttrIdx(this);
if (elm._isDefAttr(idx) == false)
return true;
String[] attrs = elm._getDefAttrs();
if (value != attrs[(idx << 2) + 3])
return true;
return false;
}
/**
* Returns the value of this attribute.
* On retrieval, the value of the attribute is returned as a string.
* Character and general entity references are replaced with their
* values. See also the method <code>getAttribute</code> on the
* <code>Element</code> interface.
* <br>On setting, this creates a <code>Text</code> node with the unparsed
* contents of the string. I.e. any characters that an XML processor
* would recognize as markup are instead treated as literal text. See
* also the method <code>setAttribute</code> on the <code>Element</code>
* interface.
*/
public String getValue()
{
return value;
}
/**
* Sets the value of this attribute.
* On setting, this creates a <code>Text</code> node with the unparsed
* contents of the string. I.e. any characters that an XML processor
* would recognize as markup are instead treated as literal text. See
* also the method <code>setAttribute</code> on the <code>Element</code>
* interface.
*
* @exception DOMException
* NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly.
*/
public void setValue(String value)
throws DOMException
{
if (_isRO())
throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, "");
XElm elm = (XElm)_getParent();
if (elm != null)
elm._updateAttr(
elm._setAttr(getNamespaceURI(), getNodeName(), value));
else
_setValue(value);
}
/**
* The value of this node, depending on its type.
* When it is defined to be <code>null</code>, setting it has no effect.
*
* @exception DOMException
* DOMSTRING_SIZE_ERR: Raised when it would return more characters than
* fit in a <code>DOMString</code> variable on the implementation
* platform.
*/
public String getNodeValue()
throws DOMException
{
return value;
}
/**
* The value of this node, depending on its type.
* When it is defined to be <code>null</code>, setting it has no effect.
*
* @exception DOMException
* NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly.
* @exception DOMException
* DOMSTRING_SIZE_ERR: Raised when it would return more characters than
* fit in a <code>DOMString</code> variable on the implementation
* platform.
*/
public void setNodeValue(String nodeValue)
throws DOMException
{
setValue(nodeValue);
}
/**
* The <code>Element</code> node this attribute is attached to or
* <code>null</code> if this attribute is not in use.
*
* @since DOM Level 2
*/
public Element getOwnerElement()
{
return (Element)_getParent();
}
/**
* Returns whether this attribute is known to be of type ID or not.
* In other words, whether this attribute
* contains an identifier for its owner element or not. When it is and
* its value is unique, the <code>ownerElement</code> of this attribute
* can be retrieved using the method <code>Document.getElementById</code>.
*
* @since DOM Level 3
*/
public boolean isId()
{
XElm elm = (XElm)_getParent();
if (elm != null) {
int idx = elm._getAttrIdx(null, getNodeName());
if (idx < 0)
throw new RuntimeException();
return elm._isIdAttr(idx);
}
return false;
}
/**
* Sets node's value attribute. This method sets the attribute value and
* adjusts list of children. A single child Text node is created unless
* the value is the empty string.
*/
protected void _setValue(String value)
{
setTextContent(value);
this.value = value;
}
/**
* Updates node's value attributes. This method updates attribute node
* internal cache of value and sync up with the parent element if any.
* It is used for the attribute value update when one of the attribute
* children have changed its value.
*/
protected void _updateValue(String value)
{
this.value = value;
XElm elm = (XElm)_getParent();
if (elm != null)
elm._setAttr(elm._getAttrIdx(this), value);
}
/**
* Cleans up node.
*/
protected void _clear()
{
super._clear();
value = "";
}
/**
* Check a new child node. This method throws appropriate exception if this
* node does not like new child. A subclass MUST chain this method with
* implementation provided by its parent class.
*/
protected void _checkNewChild(Node newChild, boolean replaceChild)
throws DOMException
{
super._checkNewChild(newChild, replaceChild);
switch(newChild.getNodeType()) {
case TEXT_NODE:
case ENTITY_REFERENCE_NODE:
break;
default:
throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, "");
}
}
/**
* Notification of child addition.
*/
protected void _childAdded(XNode child)
{
super._childAdded(child);
_updateValue(getTextContent());
}
/**
* Notification of child removal.
*/
protected void _childRemoved(XNode child)
{
super._childRemoved(child);
_updateValue(getTextContent());
}
}