/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 1999-2002 The Apache Software Foundation. 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 following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Xerces" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* 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 APACHE SOFTWARE FOUNDATION OR
* ITS 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 Apache Software Foundation and was
* originally based on software copyright (c) 1999, International
* Business Machines, Inc., http://www.apache.org. For more
* information on the Apache Software Foundation, please see
*
* Elements may have Attributes associated with them; the API for this is * defined in Node, but the function is implemented here. In general, XML * applications should retrive Attributes as Nodes, since they may contain * entity references and hence be a fairly complex sub-tree. HTML users will * be dealing with simple string values, and convenience methods are provided * to work in terms of Strings. *
* ElementImpl does not support Namespaces. ElementNSImpl, which inherits from * it, does. * @see ElementNSImpl * * @author Arnaud Le Hors, IBM * @author Joe Kesselman, IBM * @author Andy Clark, IBM * @author Ralf Pfeiffer, IBM * @version $Id: ElementImpl.java,v 1.64 2004/01/18 17:39:36 elena Exp $ * @since PR-DOM-Level-1-19980818. */ public class ElementImpl extends ParentNode implements Element { // // Constants // /** Serialization version. */ static final long serialVersionUID = 3717253516652722278L; // // Data // /** Element name. */ protected String name; /** Attributes. */ protected AttributeMap attributes; /** DOM3: type information */ // REVISIT: we are losing the type information in DOM during serialization transient TypeInfo type; // // Constructors // /** Factory constructor. */ public ElementImpl(CoreDocumentImpl ownerDoc, String name) { super(ownerDoc); this.name = name; needsSyncData(true); // synchronizeData will initialize attributes } // for ElementNSImpl protected ElementImpl() {} // Support for DOM Level 3 renameNode method. // Note: This only deals with part of the pb. CoreDocumentImpl // does all the work. void rename(String name) { if (needsSyncData()) { synchronizeData(); } this.name = name; reconcileDefaultAttributes(); } // // Node methods // /** * A short integer indicating what type of node this is. The named * constants for this value are defined in the org.w3c.dom.Node interface. */ public short getNodeType() { return Node.ELEMENT_NODE; } /** * Returns the element name */ public String getNodeName() { if (needsSyncData()) { synchronizeData(); } return name; } /** * Retrieve all the Attributes as a set. Note that this API is inherited * from Node rather than specified on Element; in fact only Elements will * ever have Attributes, but they want to allow folks to "blindly" operate * on the tree as a set of Nodes. */ public NamedNodeMap getAttributes() { if (needsSyncData()) { synchronizeData(); } if (attributes == null) { attributes = new AttributeMap(this, null); } return attributes; } // getAttributes():NamedNodeMap /** * Return a duplicate copy of this Element. Note that its children * will not be copied unless the "deep" flag is true, but Attributes * are always replicated. * * @see org.w3c.dom.Node#cloneNode(boolean) */ public Node cloneNode(boolean deep) { ElementImpl newnode = (ElementImpl) super.cloneNode(deep); // Replicate NamedNodeMap rather than sharing it. if (attributes != null) { newnode.attributes = (AttributeMap) attributes.cloneMap(newnode); } return newnode; } // cloneNode(boolean):Node /** * DOM Level 3 WD - Experimental. * Retrieve baseURI */ public String getBaseURI() { if (needsSyncData()) { synchronizeData(); } // Absolute base URI is computed according to // XML Base (http://www.w3.org/TR/xmlbase/#granularity) // 1. The base URI specified by an xml:base attribute on the element, // if one exists if (attributes != null) { Attr attrNode = (Attr)attributes.getNamedItem("xml:base"); if (attrNode != null) { String uri = attrNode.getNodeValue(); if (uri.length() != 0 ) {// attribute value is always empty string try { uri = new URI(uri).toString(); } catch (com.sun.org.apache.xerces.internal.util.URI.MalformedURIException e){ return null; } return uri; } } } // 2.the base URI of the element's parent element within the // document or external entity, if one exists // 3. the base URI of the document entity or external entity // containing the element // ownerNode serves as a parent or as document String baseURI = (this.ownerNode != null) ? this.ownerNode.getBaseURI() : null ; //base URI of parent element is not null if(baseURI != null){ try { //return valid absolute base URI return new URI(baseURI).toString(); } catch (com.sun.org.apache.xerces.internal.util.URI.MalformedURIException e){ return null; } } return null; } //getBaseURI /** * NON-DOM * set the ownerDocument of this node, its children, and its attributes */ void setOwnerDocument(CoreDocumentImpl doc) { super.setOwnerDocument(doc); if (attributes != null) { attributes.setOwnerDocument(doc); } } // // Element methods // /** * Look up a single Attribute by name. Returns the Attribute's * string value, or an empty string (NOT null!) to indicate that the * name did not map to a currently defined attribute. *
* Note: Attributes may contain complex node trees. This method * returns the "flattened" string obtained from Attribute.getValue(). * If you need the structure information, see getAttributeNode(). */ public String getAttribute(String name) { if (needsSyncData()) { synchronizeData(); } if (attributes == null) { return ""; } Attr attr = (Attr)(attributes.getNamedItem(name)); return (attr == null) ? "" : attr.getValue(); } // getAttribute(String):String /** * Look up a single Attribute by name. Returns the Attribute Node, * so its complete child tree is available. This could be important in * XML, where the string rendering may not be sufficient information. *
* If no matching attribute is available, returns null. */ public Attr getAttributeNode(String name) { if (needsSyncData()) { synchronizeData(); } if (attributes == null) { return null; } return (Attr)attributes.getNamedItem(name); } // getAttributeNode(String):Attr /** * Returns a NodeList of all descendent nodes (children, * grandchildren, and so on) which are Elements and which have the * specified tag name. *
* Note: NodeList is a "live" view of the DOM. Its contents will * change as the DOM changes, and alterations made to the NodeList * will be reflected in the DOM. * * @param tagname The type of element to gather. To obtain a list of * all elements no matter what their names, use the wild-card tag * name "*". * * @see DeepNodeListImpl */ public NodeList getElementsByTagName(String tagname) { return new DeepNodeListImpl(this,tagname); } /** * Returns the name of the Element. Note that Element.nodeName() is * defined to also return the tag name. *
* This is case-preserving in XML. HTML should uppercasify it on the * way in. */ public String getTagName() { if (needsSyncData()) { synchronizeData(); } return name; } /** * In "normal form" (as read from a source file), there will never be two * Text children in succession. But DOM users may create successive Text * nodes in the course of manipulating the document. Normalize walks the * sub-tree and merges adjacent Texts, as if the DOM had been written out * and read back in again. This simplifies implementation of higher-level * functions that may want to assume that the document is in standard form. *
* To normalize a Document, normalize its top-level Element child. *
* As of PR-DOM-Level-1-19980818, CDATA -- despite being a subclass of
* Text -- is considered "markup" and will _not_ be merged either with
* normal Text or with other CDATASections.
*/
public void normalize() {
// No need to normalize if already normalized.
if (isNormalized()) {
return;
}
if (needsSyncChildren()) {
synchronizeChildren();
}
ChildNode kid, next;
for (kid = firstChild; kid != null; kid = next) {
next = kid.nextSibling;
// If kid is a text node, we need to check for one of two
// conditions:
// 1) There is an adjacent text node
// 2) There is no adjacent text node, but kid is
// an empty text node.
if ( kid.getNodeType() == Node.TEXT_NODE )
{
// If an adjacent text node, merge it with kid
if ( next!=null && next.getNodeType() == Node.TEXT_NODE )
{
((Text)kid).appendData(next.getNodeValue());
removeChild( next );
next = kid; // Don't advance; there might be another.
}
else
{
// If kid is empty, remove it
if ( kid.getNodeValue().length()==0 )
removeChild( kid );
}
}
// Otherwise it might be an Element, which is handled recursively
else if (kid.getNodeType() == Node.ELEMENT_NODE) {
kid.normalize();
}
}
// We must also normalize all of the attributes
if ( attributes!=null )
{
for( int i=0; i
* Note that this call "succeeds" even if no attribute by this name
* existed -- unlike removeAttributeNode, which will throw a not-found
* exception in that case.
*
* @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if the node is
* readonly.
*/
public void removeAttribute(String name) {
if (ownerDocument.errorChecking && isReadOnly()) {
String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
}
if (needsSyncData()) {
synchronizeData();
}
if (attributes == null) {
return;
}
attributes.safeRemoveNamedItem(name);
} // removeAttribute(String)
/**
* Remove the specified attribute/value pair. If the removed
* Attribute has a default value, it is immediately replaced.
*
* NOTE: Specifically removes THIS NODE -- not the node with this
* name, nor the node with these contents. If the specific Attribute
* object passed in is not stored in this Element, we throw a
* DOMException. If you really want to remove an attribute by name,
* use removeAttribute().
*
* @return the Attribute object that was removed.
* @throws DOMException(NOT_FOUND_ERR) if oldattr is not an attribute of
* this Element.
* @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if the node is
* readonly.
*/
public Attr removeAttributeNode(Attr oldAttr)
throws DOMException {
if (ownerDocument.errorChecking && isReadOnly()) {
String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
}
if (needsSyncData()) {
synchronizeData();
}
if (attributes == null) {
String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null);
throw new DOMException(DOMException.NOT_FOUND_ERR, msg);
}
return (Attr) attributes.removeItem(oldAttr, true);
} // removeAttributeNode(Attr):Attr
/**
* Add a new name/value pair, or replace the value of the existing
* attribute having that name.
*
* Note: this method supports only the simplest kind of Attribute,
* one whose value is a string contained in a single Text node.
* If you want to assert a more complex value (which XML permits,
* though HTML doesn't), see setAttributeNode().
*
* The attribute is created with specified=true, meaning it's an
* explicit value rather than inherited from the DTD as a default.
* Again, setAttributeNode can be used to achieve other results.
*
* @throws DOMException(INVALID_NAME_ERR) if the name is not acceptable.
* (Attribute factory will do that test for us.)
*
* @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if the node is
* readonly.
*/
public void setAttribute(String name, String value) {
if (ownerDocument.errorChecking && isReadOnly()) {
String msg =
DOMMessageFormatter.formatMessage(
DOMMessageFormatter.DOM_DOMAIN,
"NO_MODIFICATION_ALLOWED_ERR",
null);
throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
}
if (needsSyncData()) {
synchronizeData();
}
Attr newAttr = getAttributeNode(name);
if (newAttr == null) {
newAttr = getOwnerDocument().createAttribute(name);
if (attributes == null) {
attributes = new AttributeMap(this, null);
}
newAttr.setNodeValue(value);
attributes.setNamedItem(newAttr);
}
else {
newAttr.setNodeValue(value);
}
} // setAttribute(String,String)
/**
* Add a new attribute/value pair, or replace the value of the
* existing attribute with that name.
*
* This method allows you to add an Attribute that has already been
* constructed, and hence avoids the limitations of the simple
* setAttribute() call. It can handle attribute values that have
* arbitrarily complex tree structure -- in particular, those which
* had entity references mixed into their text.
*
* @throws DOMException(INUSE_ATTRIBUTE_ERR) if the Attribute object
* has already been assigned to another Element.
*/
public Attr setAttributeNode(Attr newAttr)
throws DOMException
{
if (needsSyncData()) {
synchronizeData();
}
if (ownerDocument.errorChecking) {
if (isReadOnly()) {
String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
throw new DOMException(
DOMException.NO_MODIFICATION_ALLOWED_ERR,
msg);
}
if (newAttr.getOwnerDocument() != ownerDocument) {
String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null);
throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, msg);
}
}
if (attributes == null) {
attributes = new AttributeMap(this, null);
}
// This will throw INUSE if necessary
return (Attr) attributes.setNamedItem(newAttr);
} // setAttributeNode(Attr):Attr
//
// DOM2: Namespace methods
//
/**
* Introduced in DOM Level 2.
*
* Retrieves an attribute value by local name and namespace URI.
*
* @param namespaceURI
* The namespace URI of the attribute to
* retrieve.
* @param localName The local name of the attribute to retrieve.
* @return String The Attr value as a string, or empty string
* if that attribute
* does not have a specified or default value.
* @since WD-DOM-Level-2-19990923
*/
public String getAttributeNS(String namespaceURI, String localName) {
if (needsSyncData()) {
synchronizeData();
}
if (attributes == null) {
return "";
}
Attr attr = (Attr)(attributes.getNamedItemNS(namespaceURI, localName));
return (attr == null) ? "" : attr.getValue();
} // getAttributeNS(String,String):String
/**
* Introduced in DOM Level 2.
*
* Adds a new attribute.
* If the given namespaceURI is null or an empty string and the
* qualifiedName has a prefix that is "xml", the new attribute is bound to
* the predefined namespace "http://www.w3.org/XML/1998/namespace"
* [Namespaces]. If an attribute with the same local name and namespace
* URI is already present on the element, its prefix is changed to be the
* prefix part of the qualifiedName, and its value is changed to be the
* value parameter. This value is a simple string, it is not parsed as it
* is being set. So any markup (such as syntax to be recognized as an
* entity reference) is treated as literal text, and needs to be
* appropriately escaped by the implementation when it is written out. In
* order to assign an attribute value that contains entity references, the
* user must create an Attr node plus any Text and EntityReference nodes,
* build the appropriate subtree, and use setAttributeNodeNS or
* setAttributeNode to assign it as the value of an attribute.
*
* @param namespaceURI The namespace URI of the attribute to create
* or alter.
* @param qualifiedName The qualified name of the attribute to create or
* alter.
* @param value The value to set in string form.
* @throws INVALID_CHARACTER_ERR: Raised if the specified
* name contains an invalid character.
*
* @throws NO_MODIFICATION_ALLOWED_ERR: Raised if this
* node is readonly.
*
* @throws NAMESPACE_ERR: Raised if the qualifiedName
* has a prefix that is "xml" and the namespaceURI
* is neither null nor an empty string nor
* "http://www.w3.org/XML/1998/namespace", or if
* the qualifiedName has a prefix that is "xmlns"
* but the namespaceURI is neither null nor an
* empty string, or if if the qualifiedName has a
* prefix different from "xml" and "xmlns" and the
* namespaceURI is null or an empty string.
* @since WD-DOM-Level-2-19990923
*/
public void setAttributeNS(String namespaceURI,String qualifiedName,
String value) {
if (ownerDocument.errorChecking && isReadOnly()) {
String msg =
DOMMessageFormatter.formatMessage(
DOMMessageFormatter.DOM_DOMAIN,
"NO_MODIFICATION_ALLOWED_ERR",
null);
throw new DOMException(
DOMException.NO_MODIFICATION_ALLOWED_ERR,
msg);
}
if (needsSyncData()) {
synchronizeData();
}
int index = qualifiedName.indexOf(':');
String prefix, localName;
if (index < 0) {
prefix = null;
localName = qualifiedName;
}
else {
prefix = qualifiedName.substring(0, index);
localName = qualifiedName.substring(index + 1);
}
Attr newAttr = getAttributeNodeNS(namespaceURI, localName);
if (newAttr == null) {
// REVISIT: this is not efficient, we are creating twice the same
// strings for prefix and localName.
newAttr = getOwnerDocument().createAttributeNS(
namespaceURI,
qualifiedName);
if (attributes == null) {
attributes = new AttributeMap(this, null);
}
newAttr.setNodeValue(value);
attributes.setNamedItemNS(newAttr);
}
else {
if (newAttr instanceof AttrNSImpl){
// change prefix and value
((AttrNSImpl)newAttr).name= (prefix!=null)?(prefix+":"+localName):localName;
}
else {
// This case may happen if user calls:
// elem.setAttribute("name", "value");
// elem.setAttributeNS(null, "name", "value");
// This case is not defined by the DOM spec, we choose
// to create a new attribute in this case and remove an old one from the tree
// note this might cause events to be propagated or user data to be lost
newAttr = new AttrNSImpl((CoreDocumentImpl)getOwnerDocument(), namespaceURI, qualifiedName, localName);
attributes.setNamedItemNS(newAttr);
}
newAttr.setNodeValue(value);
}
} // setAttributeNS(String,String,String)
/**
* Introduced in DOM Level 2.
*
* Removes an attribute by local name and namespace URI. If the removed
* attribute has a default value it is immediately replaced.
* The replacing attribute has the same namespace URI and local name,
* as well as the original prefix.
*
* @param namespaceURI The namespace URI of the attribute to remove.
*
* @param localName The local name of the attribute to remove.
* @throws NO_MODIFICATION_ALLOWED_ERR: Raised if this
* node is readonly.
* @since WD-DOM-Level-2-19990923
*/
public void removeAttributeNS(String namespaceURI, String localName) {
if (ownerDocument.errorChecking && isReadOnly()) {
String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
}
if (needsSyncData()) {
synchronizeData();
}
if (attributes == null) {
return;
}
attributes.safeRemoveNamedItemNS(namespaceURI, localName);
} // removeAttributeNS(String,String)
/**
* Retrieves an Attr node by local name and namespace URI.
*
* @param namespaceURI The namespace URI of the attribute to
* retrieve.
* @param localName The local name of the attribute to retrieve.
* @return Attr The Attr node with the specified attribute
* local name and namespace
* URI or null if there is no such attribute.
* @since WD-DOM-Level-2-19990923
*/
public Attr getAttributeNodeNS(String namespaceURI, String localName){
if (needsSyncData()) {
synchronizeData();
}
if (attributes == null) {
return null;
}
return (Attr)attributes.getNamedItemNS(namespaceURI, localName);
} // getAttributeNodeNS(String,String):Attr
/**
* Introduced in DOM Level 2.
*
* Adds a new attribute. If an attribute with that local name and
* namespace URI is already present in the element, it is replaced
* by the new one.
*
* @param Attr The Attr node to add to the attribute list. When
* the Node has no namespaceURI, this method behaves
* like setAttributeNode.
* @return Attr If the newAttr attribute replaces an existing attribute
* with the same local name and namespace URI, the *
* previously existing Attr node is returned, otherwise
* null is returned.
* @throws WRONG_DOCUMENT_ERR: Raised if newAttr
* was created from a different document than the one that
* created the element.
*
* @throws NO_MODIFICATION_ALLOWED_ERR: Raised if
* this node is readonly.
*
* @throws INUSE_ATTRIBUTE_ERR: Raised if newAttr is
* already an attribute of another Element object. The
* DOM user must explicitly clone Attr nodes to re-use
* them in other elements.
* @since WD-DOM-Level-2-19990923
*/
public Attr setAttributeNodeNS(Attr newAttr)
throws DOMException
{
if (needsSyncData()) {
synchronizeData();
}
if (ownerDocument.errorChecking) {
if (isReadOnly()) {
String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
throw new DOMException(
DOMException.NO_MODIFICATION_ALLOWED_ERR,
msg);
}
if (newAttr.getOwnerDocument() != ownerDocument) {
String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null);
throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, msg);
}
}
if (attributes == null) {
attributes = new AttributeMap(this, null);
}
// This will throw INUSE if necessary
return (Attr) attributes.setNamedItemNS(newAttr);
} // setAttributeNodeNS(Attr):Attr
/**
* NON-DOM: sets attribute node for this element
*/
protected int setXercesAttributeNode (Attr attr){
if (needsSyncData()) {
synchronizeData();
}
if (attributes == null) {
attributes = new AttributeMap(this, null);
}
return attributes.addItem(attr);
}
/**
* NON-DOM: get inded of an attribute
*/
protected int getXercesAttribute(String namespaceURI, String localName){
if (needsSyncData()) {
synchronizeData();
}
if (attributes == null) {
return -1;
}
return attributes.getNamedItemIndex(namespaceURI, localName);
}
/**
* Introduced in DOM Level 2.
*/
public boolean hasAttributes() {
if (needsSyncData()) {
synchronizeData();
}
return (attributes != null && attributes.getLength() != 0);
}
/**
* Introduced in DOM Level 2.
*/
public boolean hasAttribute(String name) {
return getAttributeNode(name) != null;
}
/**
* Introduced in DOM Level 2.
*/
public boolean hasAttributeNS(String namespaceURI, String localName) {
return getAttributeNodeNS(namespaceURI, localName) != null;
}
/**
* Introduced in DOM Level 2.
*
* Returns a NodeList of all the Elements with a given local name and
* namespace URI in the order in which they would be encountered in a
* preorder traversal of the Document tree, starting from this node.
*
* @param namespaceURI The namespace URI of the elements to match
* on. The special value "*" matches all
* namespaces. When it is null or an empty
* string, this method behaves like
* getElementsByTagName.
* @param localName The local name of the elements to match on.
* The special value "*" matches all local names.
* @return NodeList A new NodeList object containing all the matched
* Elements.
* @since WD-DOM-Level-2-19990923
*/
public NodeList getElementsByTagNameNS(String namespaceURI,
String localName) {
return new DeepNodeListImpl(this, namespaceURI, localName);
}
/**
* DOM Level 3 WD- Experimental.
* Override inherited behavior from NodeImpl and ParentNode to check on
* attributes
*/
public boolean isEqualNode(Node arg) {
if (!super.isEqualNode(arg)) {
return false;
}
boolean hasAttrs = hasAttributes();
if (hasAttrs != ((Element) arg).hasAttributes()) {
return false;
}
if (hasAttrs) {
NamedNodeMap map1 = getAttributes();
NamedNodeMap map2 = ((Element) arg).getAttributes();
int len = map1.getLength();
if (len != map2.getLength()) {
return false;
}
for (int i = 0; i < len; i++) {
Node n1 = map1.item(i);
if (n1.getLocalName() == null) { // DOM Level 1 Node
Node n2 = map2.getNamedItem(n1.getNodeName());
if (n2 == null || !((NodeImpl) n1).isEqualNode(n2)) {
return false;
}
}
else {
Node n2 = map2.getNamedItemNS(n1.getNamespaceURI(),
n1.getLocalName());
if (n2 == null || !((NodeImpl) n1).isEqualNode(n2)) {
return false;
}
}
}
}
return true;
}
/**
* DOM Level 3: register the given attribute node as an ID attribute
*/
public void setIdAttributeNode(Attr at, boolean makeId) {
if (needsSyncData()) {
synchronizeData();
}
if (ownerDocument.errorChecking) {
if (isReadOnly()) {
String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
throw new DOMException(
DOMException.NO_MODIFICATION_ALLOWED_ERR,
msg);
}
if (at.getOwnerElement() != this) {
String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null);
throw new DOMException(DOMException.NOT_FOUND_ERR, msg);
}
}
((AttrImpl) at).isIdAttribute(makeId);
if (!makeId) {
ownerDocument.removeIdentifier(at.getValue());
}
else {
ownerDocument.putIdentifier(at.getValue(), this);
}
}
/**
* DOM Level 3: register the given attribute node as an ID attribute
*/
public void setIdAttribute(String name, boolean makeId) {
if (needsSyncData()) {
synchronizeData();
}
Attr at = getAttributeNode(name);
if( at == null){
String msg = DOMMessageFormatter.formatMessage(
DOMMessageFormatter.DOM_DOMAIN,
"NOT_FOUND_ERR", null);
throw new DOMException(DOMException.NOT_FOUND_ERR, msg);
}
if (ownerDocument.errorChecking) {
if (isReadOnly()) {
String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
throw new DOMException(
DOMException.NO_MODIFICATION_ALLOWED_ERR,
msg);
}
if (at.getOwnerElement() != this) {
String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null);
throw new DOMException(DOMException.NOT_FOUND_ERR, msg);
}
}
((AttrImpl) at).isIdAttribute(makeId);
if (!makeId) {
ownerDocument.removeIdentifier(at.getValue());
}
else {
ownerDocument.putIdentifier(at.getValue(), this);
}
}
/**
* DOM Level 3: register the given attribute node as an ID attribute
*/
public void setIdAttributeNS(String namespaceURI, String localName,
boolean makeId) {
if (needsSyncData()) {
synchronizeData();
}
Attr at = getAttributeNodeNS(namespaceURI, localName);
if( at == null){
String msg = DOMMessageFormatter.formatMessage(
DOMMessageFormatter.DOM_DOMAIN,
"NOT_FOUND_ERR", null);
throw new DOMException(DOMException.NOT_FOUND_ERR, msg);
}
if (ownerDocument.errorChecking) {
if (isReadOnly()) {
String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
throw new DOMException(
DOMException.NO_MODIFICATION_ALLOWED_ERR,
msg);
}
if (at.getOwnerElement() != this) {
String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null);
throw new DOMException(DOMException.NOT_FOUND_ERR, msg);
}
}
((AttrImpl) at).isIdAttribute(makeId);
if (!makeId) {
ownerDocument.removeIdentifier(at.getValue());
}
else {
ownerDocument.putIdentifier(at.getValue(), this);
}
}
/**
* NON-DOM: setting type used by the DOM parser
* @see NodeImpl#setReadOnly
*/
public void setType(TypeInfo type) {
this.type = type;
}
/**
* Method getSchemaTypeInfo.
* @return TypeInfo
*/
public TypeInfo getSchemaTypeInfo(){
if (needsSyncData()) {
synchronizeData();
}
return type;
}
//
// Public methods
//
/**
* NON-DOM: Subclassed to flip the attributes' readonly switch as well.
* @see NodeImpl#setReadOnly
*/
public void setReadOnly(boolean readOnly, boolean deep) {
super.setReadOnly(readOnly,deep);
if (attributes != null) {
attributes.setReadOnly(readOnly,true);
}
}
//
// Protected methods
//
/** Synchronizes the data (name and value) for fast nodes. */
protected void synchronizeData() {
// no need to sync in the future
needsSyncData(false);
// we don't want to generate any event for this so turn them off
boolean orig = ownerDocument.getMutationEvents();
ownerDocument.setMutationEvents(false);
// attributes
setupDefaultAttributes();
// set mutation events flag back to its original value
ownerDocument.setMutationEvents(orig);
} // synchronizeData()
// support for DOM Level 3 renameNode method
// @param el The element from which to take the attributes
void moveSpecifiedAttributes(ElementImpl el) {
if (needsSyncData()) {
synchronizeData();
}
if (el.hasAttributes()) {
if (attributes == null) {
attributes = new AttributeMap(this, null);
}
attributes.moveSpecifiedAttributes(el.attributes);
}
}
/** Setup the default attributes. */
protected void setupDefaultAttributes() {
NamedNodeMapImpl defaults = getDefaultAttributes();
if (defaults != null) {
attributes = new AttributeMap(this, defaults);
}
}
/** Reconcile default attributes. */
protected void reconcileDefaultAttributes() {
if (attributes != null) {
NamedNodeMapImpl defaults = getDefaultAttributes();
attributes.reconcileDefaults(defaults);
}
}
/** Get the default attributes. */
protected NamedNodeMapImpl getDefaultAttributes() {
DocumentTypeImpl doctype =
(DocumentTypeImpl) ownerDocument.getDoctype();
if (doctype == null) {
return null;
}
ElementDefinitionImpl eldef =
(ElementDefinitionImpl)doctype.getElements()
.getNamedItem(getNodeName());
if (eldef == null) {
return null;
}
return (NamedNodeMapImpl) eldef.getAttributes();
} // getDefaultAttributes()
} // class ElementImpl