| /* |
| * reserved comment block |
| * DO NOT REMOVE OR ALTER! |
| */ |
| /* |
| * Copyright 1999-2002,2004 The Apache Software Foundation. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.sun.org.apache.xerces.internal.dom; |
| |
| import org.w3c.dom.Attr; |
| import org.w3c.dom.DOMException; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.NamedNodeMap; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.NodeList; |
| import org.w3c.dom.Text; |
| |
| import org.w3c.dom.TypeInfo; |
| import com.sun.org.apache.xerces.internal.util.URI; |
| |
| /** |
| * Elements represent most of the "markup" and structure of the |
| * document. They contain both the data for the element itself |
| * (element name and attributes), and any contained nodes, including |
| * document text (as children). |
| * <P> |
| * 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. |
| * <P> |
| * ElementImpl does not support Namespaces. ElementNSImpl, which inherits from |
| * it, does. |
| * @see ElementNSImpl |
| * |
| * @xerces.internal |
| * |
| * @author Arnaud Le Hors, IBM |
| * @author Joe Kesselman, IBM |
| * @author Andy Clark, IBM |
| * @author Ralf Pfeiffer, IBM |
| * @since PR-DOM-Level-1-19980818. |
| */ |
| public class ElementImpl |
| extends ParentNode |
| implements Element, TypeInfo { |
| |
| // |
| // Constants |
| // |
| |
| /** Serialization version. */ |
| static final long serialVersionUID = 3717253516652722278L; |
| // |
| // Data |
| // |
| |
| /** Element name. */ |
| protected String name; |
| |
| /** Attributes. */ |
| protected AttributeMap attributes; |
| |
| // |
| // 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 <i>always</i> 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) { |
| // This may be a relative URI. |
| |
| // Make any parentURI into a URI object to use with the URI(URI, String) constructor |
| String parentBaseURI = (this.ownerNode != null) ? this.ownerNode.getBaseURI() : null; |
| if (parentBaseURI != null){ |
| try{ |
| uri = new URI(new URI(parentBaseURI), uri).toString(); |
| } |
| catch (com.sun.org.apache.xerces.internal.util.URI.MalformedURIException ex){ |
| // This should never happen: parent should have checked the URI and returned null if invalid. |
| return null; |
| } |
| return uri; |
| } |
| 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. |
| * <p> |
| * 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. |
| * <p> |
| * 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. |
| * <p> |
| * 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. |
| * <p> |
| * 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. |
| * <p> |
| * To normalize a Document, normalize its top-level Element child. |
| * <p> |
| * 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() == null || 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<attributes.getLength(); ++i ) |
| { |
| Node attr = attributes.item(i); |
| attr.normalize(); |
| } |
| } |
| |
| // changed() will have occurred when the removeChild() was done, |
| // so does not have to be reissued. |
| |
| isNormalized(true); |
| } // normalize() |
| |
| /** |
| * Remove the named attribute from this Element. If the removed |
| * Attribute has a default value, it is immediately replaced thereby. |
| * <P> |
| * The default logic is actually implemented in NamedNodeMapImpl. |
| * PR-DOM-Level-1-19980818 doesn't fully address the DTD, so some |
| * of this behavior is likely to change in future versions. ????? |
| * <P> |
| * 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. |
| * <p> |
| * 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. |
| * <P> |
| * 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. <p> |
| * |
| * 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. <p> |
| * |
| * 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){ |
| String origNodeName = ((AttrNSImpl) newAttr).name; |
| String newName = (prefix!=null) ? (prefix+":"+localName) : localName; |
| |
| ((AttrNSImpl) newAttr).name = newName; |
| |
| if (!newName.equals(origNodeName)) { |
| // Note: we can't just change the name of the attribute. Names have to be in sorted |
| // order in the attributes vector because a binary search is used to locate them. |
| // If the new name has a different prefix, the list may become unsorted. |
| // Maybe it would be better to resort the list, but the simplest |
| // fix seems to be to remove the old attribute and re-insert it. |
| // -- Norman.Walsh@Sun.COM, 2 Feb 2007 |
| newAttr = (Attr) attributes.removeItem(newAttr, false); |
| attributes.addItem(newAttr); |
| } |
| } |
| 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. <p> |
| * |
| * 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.<p> |
| * |
| * @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. <p> |
| * |
| * 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. <p> |
| * |
| * 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(); |
| } |
| //if namespace uri is empty string, set it to 'null' |
| if (namespaceURI != null) { |
| namespaceURI = (namespaceURI.length() == 0)? null : namespaceURI; |
| } |
| 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); |
| } |
| } |
| |
| /** |
| * @see org.w3c.dom.TypeInfo#getTypeName() |
| */ |
| public String getTypeName() { |
| return null; |
| } |
| |
| /** |
| * @see org.w3c.dom.TypeInfo#getTypeNamespace() |
| */ |
| public String getTypeNamespace() { |
| return null; |
| } |
| |
| /** |
| * Introduced in DOM Level 3. <p> |
| * Checks if a type is derived from another by restriction. See: |
| * http://www.w3.org/TR/DOM-Level-3-Core/core.html#TypeInfo-isDerivedFrom |
| * |
| * @param ancestorNS |
| * The namspace of the ancestor type declaration |
| * @param ancestorName |
| * The name of the ancestor type declaration |
| * @param type |
| * The reference type definition |
| * |
| * @return boolean True if the type is derived by restriciton for the |
| * reference type |
| */ |
| public boolean isDerivedFrom(String typeNamespaceArg, |
| String typeNameArg, |
| int derivationMethod) { |
| |
| return false; |
| } |
| |
| /** |
| * Method getSchemaTypeInfo. |
| * @return TypeInfo |
| */ |
| public TypeInfo getSchemaTypeInfo(){ |
| if(needsSyncData()) { |
| synchronizeData(); |
| } |
| return this; |
| } |
| |
| // |
| // 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 |