286N/A/*
286N/A * reserved comment block
286N/A * DO NOT REMOVE OR ALTER!
286N/A */
286N/A/*
286N/A * Copyright 1999-2002,2004 The Apache Software Foundation.
286N/A *
286N/A * Licensed under the Apache License, Version 2.0 (the "License");
286N/A * you may not use this file except in compliance with the License.
286N/A * You may obtain a copy of the License at
286N/A *
286N/A * http://www.apache.org/licenses/LICENSE-2.0
286N/A *
286N/A * Unless required by applicable law or agreed to in writing, software
286N/A * distributed under the License is distributed on an "AS IS" BASIS,
286N/A * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
286N/A * See the License for the specific language governing permissions and
286N/A * limitations under the License.
286N/A */
286N/A
286N/Apackage com.sun.org.apache.xerces.internal.dom;
286N/A
286N/Aimport org.w3c.dom.Attr;
286N/Aimport org.w3c.dom.DOMException;
286N/Aimport org.w3c.dom.Element;
286N/Aimport org.w3c.dom.NamedNodeMap;
286N/Aimport org.w3c.dom.Node;
286N/Aimport org.w3c.dom.NodeList;
286N/Aimport org.w3c.dom.Text;
286N/A
286N/Aimport org.w3c.dom.TypeInfo;
286N/Aimport com.sun.org.apache.xerces.internal.util.URI;
286N/A
286N/A/**
286N/A * Elements represent most of the "markup" and structure of the
286N/A * document. They contain both the data for the element itself
286N/A * (element name and attributes), and any contained nodes, including
286N/A * document text (as children).
286N/A * <P>
286N/A * Elements may have Attributes associated with them; the API for this is
286N/A * defined in Node, but the function is implemented here. In general, XML
286N/A * applications should retrive Attributes as Nodes, since they may contain
286N/A * entity references and hence be a fairly complex sub-tree. HTML users will
286N/A * be dealing with simple string values, and convenience methods are provided
286N/A * to work in terms of Strings.
286N/A * <P>
286N/A * ElementImpl does not support Namespaces. ElementNSImpl, which inherits from
286N/A * it, does.
286N/A * @see ElementNSImpl
286N/A *
286N/A * @xerces.internal
286N/A *
286N/A * @author Arnaud Le Hors, IBM
286N/A * @author Joe Kesselman, IBM
286N/A * @author Andy Clark, IBM
286N/A * @author Ralf Pfeiffer, IBM
286N/A * @since PR-DOM-Level-1-19980818.
286N/A */
286N/Apublic class ElementImpl
286N/A extends ParentNode
286N/A implements Element, TypeInfo {
286N/A
286N/A //
286N/A // Constants
286N/A //
286N/A
286N/A /** Serialization version. */
286N/A static final long serialVersionUID = 3717253516652722278L;
286N/A //
286N/A // Data
286N/A //
286N/A
286N/A /** Element name. */
286N/A protected String name;
286N/A
286N/A /** Attributes. */
286N/A protected AttributeMap attributes;
286N/A
286N/A //
286N/A // Constructors
286N/A //
286N/A
286N/A /** Factory constructor. */
286N/A public ElementImpl(CoreDocumentImpl ownerDoc, String name) {
286N/A super(ownerDoc);
286N/A this.name = name;
286N/A needsSyncData(true); // synchronizeData will initialize attributes
286N/A }
286N/A
286N/A // for ElementNSImpl
286N/A protected ElementImpl() {}
286N/A
286N/A // Support for DOM Level 3 renameNode method.
286N/A // Note: This only deals with part of the pb. CoreDocumentImpl
286N/A // does all the work.
286N/A void rename(String name) {
286N/A if (needsSyncData()) {
286N/A synchronizeData();
286N/A }
286N/A this.name = name;
286N/A reconcileDefaultAttributes();
286N/A }
286N/A
286N/A //
286N/A // Node methods
286N/A //
286N/A
286N/A
286N/A /**
286N/A * A short integer indicating what type of node this is. The named
286N/A * constants for this value are defined in the org.w3c.dom.Node interface.
286N/A */
286N/A public short getNodeType() {
286N/A return Node.ELEMENT_NODE;
286N/A }
286N/A
286N/A /**
286N/A * Returns the element name
286N/A */
286N/A public String getNodeName() {
286N/A if (needsSyncData()) {
286N/A synchronizeData();
286N/A }
286N/A return name;
286N/A }
286N/A
286N/A /**
286N/A * Retrieve all the Attributes as a set. Note that this API is inherited
286N/A * from Node rather than specified on Element; in fact only Elements will
286N/A * ever have Attributes, but they want to allow folks to "blindly" operate
286N/A * on the tree as a set of Nodes.
286N/A */
286N/A public NamedNodeMap getAttributes() {
286N/A
286N/A if (needsSyncData()) {
286N/A synchronizeData();
286N/A }
286N/A if (attributes == null) {
286N/A attributes = new AttributeMap(this, null);
286N/A }
286N/A return attributes;
286N/A
286N/A } // getAttributes():NamedNodeMap
286N/A
286N/A /**
286N/A * Return a duplicate copy of this Element. Note that its children
286N/A * will not be copied unless the "deep" flag is true, but Attributes
286N/A * are <i>always</i> replicated.
286N/A *
286N/A * @see org.w3c.dom.Node#cloneNode(boolean)
286N/A */
286N/A public Node cloneNode(boolean deep) {
286N/A
286N/A ElementImpl newnode = (ElementImpl) super.cloneNode(deep);
286N/A // Replicate NamedNodeMap rather than sharing it.
286N/A if (attributes != null) {
286N/A newnode.attributes = (AttributeMap) attributes.cloneMap(newnode);
286N/A }
286N/A return newnode;
286N/A
286N/A } // cloneNode(boolean):Node
286N/A
286N/A /**
286N/A * DOM Level 3 WD - Experimental.
286N/A * Retrieve baseURI
286N/A */
286N/A public String getBaseURI() {
286N/A
286N/A if (needsSyncData()) {
286N/A synchronizeData();
286N/A }
286N/A // Absolute base URI is computed according to
286N/A // XML Base (http://www.w3.org/TR/xmlbase/#granularity)
286N/A // 1. The base URI specified by an xml:base attribute on the element,
286N/A // if one exists
286N/A if (attributes != null) {
286N/A Attr attrNode = (Attr)attributes.getNamedItem("xml:base");
286N/A if (attrNode != null) {
286N/A String uri = attrNode.getNodeValue();
286N/A if (uri.length() != 0 ) {// attribute value is always empty string
286N/A try {
286N/A uri = new URI(uri).toString();
286N/A }
286N/A catch (com.sun.org.apache.xerces.internal.util.URI.MalformedURIException e) {
286N/A // This may be a relative URI.
286N/A
286N/A // Make any parentURI into a URI object to use with the URI(URI, String) constructor
286N/A String parentBaseURI = (this.ownerNode != null) ? this.ownerNode.getBaseURI() : null;
286N/A if (parentBaseURI != null){
286N/A try{
286N/A uri = new URI(new URI(parentBaseURI), uri).toString();
286N/A }
286N/A catch (com.sun.org.apache.xerces.internal.util.URI.MalformedURIException ex){
286N/A // This should never happen: parent should have checked the URI and returned null if invalid.
286N/A return null;
286N/A }
286N/A return uri;
286N/A }
286N/A return null;
286N/A }
286N/A return uri;
286N/A }
286N/A }
286N/A }
286N/A
286N/A // 2.the base URI of the element's parent element within the
286N/A // document or external entity, if one exists
286N/A // 3. the base URI of the document entity or external entity
286N/A // containing the element
286N/A
286N/A // ownerNode serves as a parent or as document
286N/A String baseURI = (this.ownerNode != null) ? this.ownerNode.getBaseURI() : null ;
286N/A //base URI of parent element is not null
286N/A if(baseURI != null){
286N/A try {
286N/A //return valid absolute base URI
286N/A return new URI(baseURI).toString();
286N/A }
286N/A catch (com.sun.org.apache.xerces.internal.util.URI.MalformedURIException e){
286N/A return null;
286N/A }
286N/A }
286N/A return null;
286N/A } //getBaseURI
286N/A
286N/A
286N/A
286N/A /**
286N/A * NON-DOM
286N/A * set the ownerDocument of this node, its children, and its attributes
286N/A */
286N/A void setOwnerDocument(CoreDocumentImpl doc) {
286N/A super.setOwnerDocument(doc);
286N/A if (attributes != null) {
286N/A attributes.setOwnerDocument(doc);
286N/A }
286N/A }
286N/A
286N/A //
286N/A // Element methods
286N/A //
286N/A
286N/A /**
286N/A * Look up a single Attribute by name. Returns the Attribute's
286N/A * string value, or an empty string (NOT null!) to indicate that the
286N/A * name did not map to a currently defined attribute.
286N/A * <p>
286N/A * Note: Attributes may contain complex node trees. This method
286N/A * returns the "flattened" string obtained from Attribute.getValue().
286N/A * If you need the structure information, see getAttributeNode().
286N/A */
286N/A public String getAttribute(String name) {
286N/A
286N/A if (needsSyncData()) {
286N/A synchronizeData();
286N/A }
286N/A if (attributes == null) {
286N/A return "";
286N/A }
286N/A Attr attr = (Attr)(attributes.getNamedItem(name));
286N/A return (attr == null) ? "" : attr.getValue();
286N/A
286N/A } // getAttribute(String):String
286N/A
286N/A
286N/A /**
286N/A * Look up a single Attribute by name. Returns the Attribute Node,
286N/A * so its complete child tree is available. This could be important in
286N/A * XML, where the string rendering may not be sufficient information.
286N/A * <p>
286N/A * If no matching attribute is available, returns null.
286N/A */
286N/A public Attr getAttributeNode(String name) {
286N/A
286N/A if (needsSyncData()) {
286N/A synchronizeData();
286N/A }
286N/A if (attributes == null) {
286N/A return null;
286N/A }
286N/A return (Attr)attributes.getNamedItem(name);
286N/A
286N/A } // getAttributeNode(String):Attr
286N/A
286N/A
286N/A /**
286N/A * Returns a NodeList of all descendent nodes (children,
286N/A * grandchildren, and so on) which are Elements and which have the
286N/A * specified tag name.
286N/A * <p>
286N/A * Note: NodeList is a "live" view of the DOM. Its contents will
286N/A * change as the DOM changes, and alterations made to the NodeList
286N/A * will be reflected in the DOM.
286N/A *
286N/A * @param tagname The type of element to gather. To obtain a list of
286N/A * all elements no matter what their names, use the wild-card tag
286N/A * name "*".
286N/A *
286N/A * @see DeepNodeListImpl
286N/A */
286N/A public NodeList getElementsByTagName(String tagname) {
286N/A return new DeepNodeListImpl(this,tagname);
286N/A }
286N/A
286N/A /**
286N/A * Returns the name of the Element. Note that Element.nodeName() is
286N/A * defined to also return the tag name.
286N/A * <p>
286N/A * This is case-preserving in XML. HTML should uppercasify it on the
286N/A * way in.
286N/A */
286N/A public String getTagName() {
286N/A if (needsSyncData()) {
286N/A synchronizeData();
286N/A }
286N/A return name;
286N/A }
286N/A
286N/A /**
286N/A * In "normal form" (as read from a source file), there will never be two
286N/A * Text children in succession. But DOM users may create successive Text
286N/A * nodes in the course of manipulating the document. Normalize walks the
286N/A * sub-tree and merges adjacent Texts, as if the DOM had been written out
286N/A * and read back in again. This simplifies implementation of higher-level
286N/A * functions that may want to assume that the document is in standard form.
286N/A * <p>
286N/A * To normalize a Document, normalize its top-level Element child.
286N/A * <p>
286N/A * As of PR-DOM-Level-1-19980818, CDATA -- despite being a subclass of
286N/A * Text -- is considered "markup" and will _not_ be merged either with
286N/A * normal Text or with other CDATASections.
286N/A */
286N/A public void normalize() {
286N/A // No need to normalize if already normalized.
286N/A if (isNormalized()) {
286N/A return;
286N/A }
286N/A if (needsSyncChildren()) {
286N/A synchronizeChildren();
286N/A }
286N/A ChildNode kid, next;
286N/A for (kid = firstChild; kid != null; kid = next) {
286N/A next = kid.nextSibling;
286N/A
286N/A // If kid is a text node, we need to check for one of two
286N/A // conditions:
286N/A // 1) There is an adjacent text node
286N/A // 2) There is no adjacent text node, but kid is
286N/A // an empty text node.
286N/A if ( kid.getNodeType() == Node.TEXT_NODE )
286N/A {
286N/A // If an adjacent text node, merge it with kid
286N/A if ( next!=null && next.getNodeType() == Node.TEXT_NODE )
286N/A {
286N/A ((Text)kid).appendData(next.getNodeValue());
286N/A removeChild( next );
286N/A next = kid; // Don't advance; there might be another.
286N/A }
286N/A else
286N/A {
286N/A // If kid is empty, remove it
286N/A if ( kid.getNodeValue() == null || kid.getNodeValue().length() == 0 ) {
286N/A removeChild( kid );
286N/A }
286N/A }
286N/A }
286N/A
286N/A // Otherwise it might be an Element, which is handled recursively
286N/A else if (kid.getNodeType() == Node.ELEMENT_NODE) {
286N/A kid.normalize();
286N/A }
286N/A }
286N/A
286N/A // We must also normalize all of the attributes
286N/A if ( attributes!=null )
286N/A {
286N/A for( int i=0; i<attributes.getLength(); ++i )
286N/A {
286N/A Node attr = attributes.item(i);
286N/A attr.normalize();
286N/A }
286N/A }
286N/A
286N/A // changed() will have occurred when the removeChild() was done,
286N/A // so does not have to be reissued.
286N/A
286N/A isNormalized(true);
286N/A } // normalize()
286N/A
286N/A /**
286N/A * Remove the named attribute from this Element. If the removed
286N/A * Attribute has a default value, it is immediately replaced thereby.
286N/A * <P>
286N/A * The default logic is actually implemented in NamedNodeMapImpl.
286N/A * PR-DOM-Level-1-19980818 doesn't fully address the DTD, so some
286N/A * of this behavior is likely to change in future versions. ?????
286N/A * <P>
286N/A * Note that this call "succeeds" even if no attribute by this name
286N/A * existed -- unlike removeAttributeNode, which will throw a not-found
286N/A * exception in that case.
286N/A *
286N/A * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if the node is
286N/A * readonly.
286N/A */
286N/A public void removeAttribute(String name) {
286N/A
286N/A if (ownerDocument.errorChecking && isReadOnly()) {
286N/A String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
286N/A throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
286N/A }
286N/A
286N/A if (needsSyncData()) {
286N/A synchronizeData();
286N/A }
286N/A
286N/A if (attributes == null) {
286N/A return;
286N/A }
286N/A
286N/A attributes.safeRemoveNamedItem(name);
286N/A
286N/A } // removeAttribute(String)
286N/A
286N/A
286N/A /**
286N/A * Remove the specified attribute/value pair. If the removed
286N/A * Attribute has a default value, it is immediately replaced.
286N/A * <p>
286N/A * NOTE: Specifically removes THIS NODE -- not the node with this
286N/A * name, nor the node with these contents. If the specific Attribute
286N/A * object passed in is not stored in this Element, we throw a
286N/A * DOMException. If you really want to remove an attribute by name,
286N/A * use removeAttribute().
286N/A *
286N/A * @return the Attribute object that was removed.
286N/A * @throws DOMException(NOT_FOUND_ERR) if oldattr is not an attribute of
286N/A * this Element.
286N/A * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if the node is
286N/A * readonly.
286N/A */
286N/A public Attr removeAttributeNode(Attr oldAttr)
286N/A throws DOMException {
286N/A
286N/A if (ownerDocument.errorChecking && isReadOnly()) {
286N/A String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
286N/A throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
286N/A }
286N/A
286N/A if (needsSyncData()) {
286N/A synchronizeData();
286N/A }
286N/A
286N/A if (attributes == null) {
286N/A String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null);
286N/A throw new DOMException(DOMException.NOT_FOUND_ERR, msg);
286N/A }
286N/A return (Attr) attributes.removeItem(oldAttr, true);
286N/A
286N/A } // removeAttributeNode(Attr):Attr
286N/A
286N/A
286N/A /**
286N/A * Add a new name/value pair, or replace the value of the existing
286N/A * attribute having that name.
286N/A *
286N/A * Note: this method supports only the simplest kind of Attribute,
286N/A * one whose value is a string contained in a single Text node.
286N/A * If you want to assert a more complex value (which XML permits,
286N/A * though HTML doesn't), see setAttributeNode().
286N/A *
286N/A * The attribute is created with specified=true, meaning it's an
286N/A * explicit value rather than inherited from the DTD as a default.
286N/A * Again, setAttributeNode can be used to achieve other results.
286N/A *
286N/A * @throws DOMException(INVALID_NAME_ERR) if the name is not acceptable.
286N/A * (Attribute factory will do that test for us.)
286N/A *
286N/A * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if the node is
286N/A * readonly.
286N/A */
286N/A public void setAttribute(String name, String value) {
286N/A
286N/A if (ownerDocument.errorChecking && isReadOnly()) {
286N/A String msg =
286N/A DOMMessageFormatter.formatMessage(
286N/A DOMMessageFormatter.DOM_DOMAIN,
286N/A "NO_MODIFICATION_ALLOWED_ERR",
286N/A null);
286N/A throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
286N/A }
286N/A
286N/A if (needsSyncData()) {
286N/A synchronizeData();
286N/A }
286N/A
286N/A Attr newAttr = getAttributeNode(name);
286N/A if (newAttr == null) {
286N/A newAttr = getOwnerDocument().createAttribute(name);
286N/A
286N/A if (attributes == null) {
286N/A attributes = new AttributeMap(this, null);
286N/A }
286N/A
286N/A newAttr.setNodeValue(value);
286N/A attributes.setNamedItem(newAttr);
286N/A }
286N/A else {
286N/A newAttr.setNodeValue(value);
286N/A }
286N/A
286N/A } // setAttribute(String,String)
286N/A
286N/A /**
286N/A * Add a new attribute/value pair, or replace the value of the
286N/A * existing attribute with that name.
286N/A * <P>
286N/A * This method allows you to add an Attribute that has already been
286N/A * constructed, and hence avoids the limitations of the simple
286N/A * setAttribute() call. It can handle attribute values that have
286N/A * arbitrarily complex tree structure -- in particular, those which
286N/A * had entity references mixed into their text.
286N/A *
286N/A * @throws DOMException(INUSE_ATTRIBUTE_ERR) if the Attribute object
286N/A * has already been assigned to another Element.
286N/A */
286N/A public Attr setAttributeNode(Attr newAttr)
286N/A throws DOMException
286N/A {
286N/A
286N/A if (needsSyncData()) {
286N/A synchronizeData();
286N/A }
286N/A
286N/A if (ownerDocument.errorChecking) {
286N/A if (isReadOnly()) {
286N/A String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
286N/A throw new DOMException(
286N/A DOMException.NO_MODIFICATION_ALLOWED_ERR,
286N/A msg);
286N/A }
286N/A
286N/A if (newAttr.getOwnerDocument() != ownerDocument) {
286N/A String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null);
286N/A throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, msg);
286N/A }
286N/A }
286N/A
286N/A if (attributes == null) {
286N/A attributes = new AttributeMap(this, null);
286N/A }
286N/A // This will throw INUSE if necessary
286N/A return (Attr) attributes.setNamedItem(newAttr);
286N/A
286N/A } // setAttributeNode(Attr):Attr
286N/A
286N/A //
286N/A // DOM2: Namespace methods
286N/A //
286N/A
286N/A /**
286N/A * Introduced in DOM Level 2. <p>
286N/A *
286N/A * Retrieves an attribute value by local name and namespace URI.
286N/A *
286N/A * @param namespaceURI
286N/A * The namespace URI of the attribute to
286N/A * retrieve.
286N/A * @param localName The local name of the attribute to retrieve.
286N/A * @return String The Attr value as a string, or empty string
286N/A * if that attribute
286N/A * does not have a specified or default value.
286N/A * @since WD-DOM-Level-2-19990923
286N/A */
286N/A public String getAttributeNS(String namespaceURI, String localName) {
286N/A
286N/A if (needsSyncData()) {
286N/A synchronizeData();
286N/A }
286N/A
286N/A if (attributes == null) {
286N/A return "";
286N/A }
286N/A
286N/A Attr attr = (Attr)(attributes.getNamedItemNS(namespaceURI, localName));
286N/A return (attr == null) ? "" : attr.getValue();
286N/A
286N/A } // getAttributeNS(String,String):String
286N/A
286N/A /**
286N/A * Introduced in DOM Level 2. <p>
286N/A *
286N/A * Adds a new attribute.
286N/A * If the given namespaceURI is null or an empty string and the
286N/A * qualifiedName has a prefix that is "xml", the new attribute is bound to
286N/A * the predefined namespace "http://www.w3.org/XML/1998/namespace"
286N/A * [Namespaces]. If an attribute with the same local name and namespace
286N/A * URI is already present on the element, its prefix is changed to be the
286N/A * prefix part of the qualifiedName, and its value is changed to be the
286N/A * value parameter. This value is a simple string, it is not parsed as it
286N/A * is being set. So any markup (such as syntax to be recognized as an
286N/A * entity reference) is treated as literal text, and needs to be
286N/A * appropriately escaped by the implementation when it is written out. In
286N/A * order to assign an attribute value that contains entity references, the
286N/A * user must create an Attr node plus any Text and EntityReference nodes,
286N/A * build the appropriate subtree, and use setAttributeNodeNS or
286N/A * setAttributeNode to assign it as the value of an attribute.
286N/A *
286N/A * @param namespaceURI The namespace URI of the attribute to create
286N/A * or alter.
286N/A * @param qualifiedName The qualified name of the attribute to create or
286N/A * alter.
286N/A * @param value The value to set in string form.
286N/A * @throws INVALID_CHARACTER_ERR: Raised if the specified
286N/A * name contains an invalid character.
286N/A *
286N/A * @throws NO_MODIFICATION_ALLOWED_ERR: Raised if this
286N/A * node is readonly.
286N/A *
286N/A * @throws NAMESPACE_ERR: Raised if the qualifiedName
286N/A * has a prefix that is "xml" and the namespaceURI
286N/A * is neither null nor an empty string nor
286N/A * "http://www.w3.org/XML/1998/namespace", or if
286N/A * the qualifiedName has a prefix that is "xmlns"
286N/A * but the namespaceURI is neither null nor an
286N/A * empty string, or if if the qualifiedName has a
286N/A * prefix different from "xml" and "xmlns" and the
286N/A * namespaceURI is null or an empty string.
286N/A * @since WD-DOM-Level-2-19990923
286N/A */
286N/A public void setAttributeNS(String namespaceURI,String qualifiedName,
286N/A String value) {
286N/A if (ownerDocument.errorChecking && isReadOnly()) {
286N/A String msg =
286N/A DOMMessageFormatter.formatMessage(
286N/A DOMMessageFormatter.DOM_DOMAIN,
286N/A "NO_MODIFICATION_ALLOWED_ERR",
286N/A null);
286N/A throw new DOMException(
286N/A DOMException.NO_MODIFICATION_ALLOWED_ERR,
286N/A msg);
286N/A }
286N/A if (needsSyncData()) {
286N/A synchronizeData();
286N/A }
286N/A int index = qualifiedName.indexOf(':');
286N/A String prefix, localName;
286N/A if (index < 0) {
286N/A prefix = null;
286N/A localName = qualifiedName;
286N/A }
286N/A else {
286N/A prefix = qualifiedName.substring(0, index);
286N/A localName = qualifiedName.substring(index + 1);
286N/A }
286N/A Attr newAttr = getAttributeNodeNS(namespaceURI, localName);
286N/A if (newAttr == null) {
286N/A // REVISIT: this is not efficient, we are creating twice the same
286N/A // strings for prefix and localName.
286N/A newAttr = getOwnerDocument().createAttributeNS(
286N/A namespaceURI,
286N/A qualifiedName);
286N/A if (attributes == null) {
286N/A attributes = new AttributeMap(this, null);
286N/A }
286N/A newAttr.setNodeValue(value);
286N/A attributes.setNamedItemNS(newAttr);
286N/A }
286N/A else {
286N/A if (newAttr instanceof AttrNSImpl){
286N/A String origNodeName = ((AttrNSImpl) newAttr).name;
286N/A String newName = (prefix!=null) ? (prefix+":"+localName) : localName;
286N/A
286N/A ((AttrNSImpl) newAttr).name = newName;
286N/A
286N/A if (!newName.equals(origNodeName)) {
286N/A // Note: we can't just change the name of the attribute. Names have to be in sorted
286N/A // order in the attributes vector because a binary search is used to locate them.
286N/A // If the new name has a different prefix, the list may become unsorted.
286N/A // Maybe it would be better to resort the list, but the simplest
286N/A // fix seems to be to remove the old attribute and re-insert it.
286N/A // -- Norman.Walsh@Sun.COM, 2 Feb 2007
286N/A newAttr = (Attr) attributes.removeItem(newAttr, false);
286N/A attributes.addItem(newAttr);
286N/A }
286N/A }
286N/A else {
286N/A // This case may happen if user calls:
286N/A // elem.setAttribute("name", "value");
286N/A // elem.setAttributeNS(null, "name", "value");
286N/A // This case is not defined by the DOM spec, we choose
286N/A // to create a new attribute in this case and remove an old one from the tree
286N/A // note this might cause events to be propagated or user data to be lost
286N/A newAttr = new AttrNSImpl((CoreDocumentImpl)getOwnerDocument(), namespaceURI, qualifiedName, localName);
286N/A attributes.setNamedItemNS(newAttr);
286N/A }
286N/A
286N/A newAttr.setNodeValue(value);
286N/A }
286N/A
286N/A } // setAttributeNS(String,String,String)
286N/A
286N/A
286N/A /**
286N/A * Introduced in DOM Level 2. <p>
286N/A *
286N/A * Removes an attribute by local name and namespace URI. If the removed
286N/A * attribute has a default value it is immediately replaced.
286N/A * The replacing attribute has the same namespace URI and local name,
286N/A * as well as the original prefix.<p>
286N/A *
286N/A * @param namespaceURI The namespace URI of the attribute to remove.
286N/A *
286N/A * @param localName The local name of the attribute to remove.
286N/A * @throws NO_MODIFICATION_ALLOWED_ERR: Raised if this
286N/A * node is readonly.
286N/A * @since WD-DOM-Level-2-19990923
286N/A */
286N/A public void removeAttributeNS(String namespaceURI, String localName) {
286N/A
286N/A if (ownerDocument.errorChecking && isReadOnly()) {
286N/A String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
286N/A throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
286N/A }
286N/A
286N/A if (needsSyncData()) {
286N/A synchronizeData();
286N/A }
286N/A
286N/A if (attributes == null) {
286N/A return;
286N/A }
286N/A
286N/A attributes.safeRemoveNamedItemNS(namespaceURI, localName);
286N/A
286N/A } // removeAttributeNS(String,String)
286N/A
286N/A /**
286N/A * Retrieves an Attr node by local name and namespace URI.
286N/A *
286N/A * @param namespaceURI The namespace URI of the attribute to
286N/A * retrieve.
286N/A * @param localName The local name of the attribute to retrieve.
286N/A * @return Attr The Attr node with the specified attribute
286N/A * local name and namespace
286N/A * URI or null if there is no such attribute.
286N/A * @since WD-DOM-Level-2-19990923
286N/A */
286N/A public Attr getAttributeNodeNS(String namespaceURI, String localName){
286N/A
286N/A if (needsSyncData()) {
286N/A synchronizeData();
286N/A }
286N/A if (attributes == null) {
286N/A return null;
286N/A }
286N/A return (Attr)attributes.getNamedItemNS(namespaceURI, localName);
286N/A
286N/A } // getAttributeNodeNS(String,String):Attr
286N/A
286N/A /**
286N/A * Introduced in DOM Level 2. <p>
286N/A *
286N/A * Adds a new attribute. If an attribute with that local name and
286N/A * namespace URI is already present in the element, it is replaced
286N/A * by the new one.
286N/A *
286N/A * @param Attr The Attr node to add to the attribute list. When
286N/A * the Node has no namespaceURI, this method behaves
286N/A * like setAttributeNode.
286N/A * @return Attr If the newAttr attribute replaces an existing attribute
286N/A * with the same local name and namespace URI, the *
286N/A * previously existing Attr node is returned, otherwise
286N/A * null is returned.
286N/A * @throws WRONG_DOCUMENT_ERR: Raised if newAttr
286N/A * was created from a different document than the one that
286N/A * created the element.
286N/A *
286N/A * @throws NO_MODIFICATION_ALLOWED_ERR: Raised if
286N/A * this node is readonly.
286N/A *
286N/A * @throws INUSE_ATTRIBUTE_ERR: Raised if newAttr is
286N/A * already an attribute of another Element object. The
286N/A * DOM user must explicitly clone Attr nodes to re-use
286N/A * them in other elements.
286N/A * @since WD-DOM-Level-2-19990923
286N/A */
286N/A public Attr setAttributeNodeNS(Attr newAttr)
286N/A throws DOMException
286N/A {
286N/A
286N/A if (needsSyncData()) {
286N/A synchronizeData();
286N/A }
286N/A if (ownerDocument.errorChecking) {
286N/A if (isReadOnly()) {
286N/A String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
286N/A throw new DOMException(
286N/A DOMException.NO_MODIFICATION_ALLOWED_ERR,
286N/A msg);
286N/A }
286N/A if (newAttr.getOwnerDocument() != ownerDocument) {
286N/A String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null);
286N/A throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, msg);
286N/A }
286N/A }
286N/A
286N/A if (attributes == null) {
286N/A attributes = new AttributeMap(this, null);
286N/A }
286N/A // This will throw INUSE if necessary
286N/A return (Attr) attributes.setNamedItemNS(newAttr);
286N/A
286N/A } // setAttributeNodeNS(Attr):Attr
286N/A
286N/A /**
286N/A * NON-DOM: sets attribute node for this element
286N/A */
286N/A protected int setXercesAttributeNode (Attr attr){
286N/A
286N/A if (needsSyncData()) {
286N/A synchronizeData();
286N/A }
286N/A
286N/A if (attributes == null) {
286N/A attributes = new AttributeMap(this, null);
286N/A }
286N/A return attributes.addItem(attr);
286N/A
286N/A }
286N/A
286N/A /**
286N/A * NON-DOM: get inded of an attribute
286N/A */
286N/A protected int getXercesAttribute(String namespaceURI, String localName){
286N/A
286N/A if (needsSyncData()) {
286N/A synchronizeData();
286N/A }
286N/A if (attributes == null) {
286N/A return -1;
286N/A }
286N/A return attributes.getNamedItemIndex(namespaceURI, localName);
286N/A
286N/A }
286N/A
286N/A /**
286N/A * Introduced in DOM Level 2.
286N/A */
286N/A public boolean hasAttributes() {
286N/A if (needsSyncData()) {
286N/A synchronizeData();
286N/A }
286N/A return (attributes != null && attributes.getLength() != 0);
286N/A }
286N/A
286N/A /**
286N/A * Introduced in DOM Level 2.
286N/A */
286N/A public boolean hasAttribute(String name) {
286N/A return getAttributeNode(name) != null;
286N/A }
286N/A
286N/A /**
286N/A * Introduced in DOM Level 2.
286N/A */
286N/A public boolean hasAttributeNS(String namespaceURI, String localName) {
286N/A return getAttributeNodeNS(namespaceURI, localName) != null;
286N/A }
286N/A
286N/A /**
286N/A * Introduced in DOM Level 2. <p>
286N/A *
286N/A * Returns a NodeList of all the Elements with a given local name and
286N/A * namespace URI in the order in which they would be encountered in a
286N/A * preorder traversal of the Document tree, starting from this node.
286N/A *
286N/A * @param namespaceURI The namespace URI of the elements to match
286N/A * on. The special value "*" matches all
286N/A * namespaces. When it is null or an empty
286N/A * string, this method behaves like
286N/A * getElementsByTagName.
286N/A * @param localName The local name of the elements to match on.
286N/A * The special value "*" matches all local names.
286N/A * @return NodeList A new NodeList object containing all the matched
286N/A * Elements.
286N/A * @since WD-DOM-Level-2-19990923
286N/A */
286N/A public NodeList getElementsByTagNameNS(String namespaceURI,
286N/A String localName) {
286N/A return new DeepNodeListImpl(this, namespaceURI, localName);
286N/A }
286N/A
286N/A /**
286N/A * DOM Level 3 WD- Experimental.
286N/A * Override inherited behavior from NodeImpl and ParentNode to check on
286N/A * attributes
286N/A */
286N/A public boolean isEqualNode(Node arg) {
286N/A if (!super.isEqualNode(arg)) {
286N/A return false;
286N/A }
286N/A boolean hasAttrs = hasAttributes();
286N/A if (hasAttrs != ((Element) arg).hasAttributes()) {
286N/A return false;
286N/A }
286N/A if (hasAttrs) {
286N/A NamedNodeMap map1 = getAttributes();
286N/A NamedNodeMap map2 = ((Element) arg).getAttributes();
286N/A int len = map1.getLength();
286N/A if (len != map2.getLength()) {
286N/A return false;
286N/A }
286N/A for (int i = 0; i < len; i++) {
286N/A Node n1 = map1.item(i);
286N/A if (n1.getLocalName() == null) { // DOM Level 1 Node
286N/A Node n2 = map2.getNamedItem(n1.getNodeName());
286N/A if (n2 == null || !((NodeImpl) n1).isEqualNode(n2)) {
286N/A return false;
286N/A }
286N/A }
286N/A else {
286N/A Node n2 = map2.getNamedItemNS(n1.getNamespaceURI(),
286N/A n1.getLocalName());
286N/A if (n2 == null || !((NodeImpl) n1).isEqualNode(n2)) {
286N/A return false;
286N/A }
286N/A }
286N/A }
286N/A }
286N/A return true;
286N/A }
286N/A
286N/A /**
286N/A * DOM Level 3: register the given attribute node as an ID attribute
286N/A */
286N/A public void setIdAttributeNode(Attr at, boolean makeId) {
286N/A if (needsSyncData()) {
286N/A synchronizeData();
286N/A }
286N/A if (ownerDocument.errorChecking) {
286N/A if (isReadOnly()) {
286N/A String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
286N/A throw new DOMException(
286N/A DOMException.NO_MODIFICATION_ALLOWED_ERR,
286N/A msg);
286N/A }
286N/A
286N/A if (at.getOwnerElement() != this) {
286N/A String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null);
286N/A throw new DOMException(DOMException.NOT_FOUND_ERR, msg);
286N/A }
286N/A }
286N/A ((AttrImpl) at).isIdAttribute(makeId);
286N/A if (!makeId) {
286N/A ownerDocument.removeIdentifier(at.getValue());
286N/A }
286N/A else {
286N/A ownerDocument.putIdentifier(at.getValue(), this);
286N/A }
286N/A }
286N/A
286N/A /**
286N/A * DOM Level 3: register the given attribute node as an ID attribute
286N/A */
286N/A public void setIdAttribute(String name, boolean makeId) {
286N/A if (needsSyncData()) {
286N/A synchronizeData();
286N/A }
286N/A Attr at = getAttributeNode(name);
286N/A
286N/A if( at == null){
286N/A String msg = DOMMessageFormatter.formatMessage(
286N/A DOMMessageFormatter.DOM_DOMAIN,
286N/A "NOT_FOUND_ERR", null);
286N/A throw new DOMException(DOMException.NOT_FOUND_ERR, msg);
286N/A }
286N/A
286N/A if (ownerDocument.errorChecking) {
286N/A if (isReadOnly()) {
286N/A String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
286N/A throw new DOMException(
286N/A DOMException.NO_MODIFICATION_ALLOWED_ERR,
286N/A msg);
286N/A }
286N/A
286N/A if (at.getOwnerElement() != this) {
286N/A String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null);
286N/A throw new DOMException(DOMException.NOT_FOUND_ERR, msg);
286N/A }
286N/A }
286N/A
286N/A ((AttrImpl) at).isIdAttribute(makeId);
286N/A if (!makeId) {
286N/A ownerDocument.removeIdentifier(at.getValue());
286N/A }
286N/A else {
286N/A ownerDocument.putIdentifier(at.getValue(), this);
286N/A }
286N/A }
286N/A
286N/A /**
286N/A * DOM Level 3: register the given attribute node as an ID attribute
286N/A */
286N/A public void setIdAttributeNS(String namespaceURI, String localName,
286N/A boolean makeId) {
286N/A if (needsSyncData()) {
286N/A synchronizeData();
286N/A }
286N/A //if namespace uri is empty string, set it to 'null'
286N/A if (namespaceURI != null) {
286N/A namespaceURI = (namespaceURI.length() == 0)? null : namespaceURI;
286N/A }
286N/A Attr at = getAttributeNodeNS(namespaceURI, localName);
286N/A
286N/A if( at == null){
286N/A String msg = DOMMessageFormatter.formatMessage(
286N/A DOMMessageFormatter.DOM_DOMAIN,
286N/A "NOT_FOUND_ERR", null);
286N/A throw new DOMException(DOMException.NOT_FOUND_ERR, msg);
286N/A }
286N/A
286N/A if (ownerDocument.errorChecking) {
286N/A if (isReadOnly()) {
286N/A String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
286N/A throw new DOMException(
286N/A DOMException.NO_MODIFICATION_ALLOWED_ERR,
286N/A msg);
286N/A }
286N/A
286N/A if (at.getOwnerElement() != this) {
286N/A String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null);
286N/A throw new DOMException(DOMException.NOT_FOUND_ERR, msg);
286N/A }
286N/A }
286N/A ((AttrImpl) at).isIdAttribute(makeId);
286N/A if (!makeId) {
286N/A ownerDocument.removeIdentifier(at.getValue());
286N/A }
286N/A else {
286N/A ownerDocument.putIdentifier(at.getValue(), this);
286N/A }
286N/A }
286N/A
286N/A /**
286N/A * @see org.w3c.dom.TypeInfo#getTypeName()
286N/A */
286N/A public String getTypeName() {
286N/A return null;
286N/A }
286N/A
286N/A /**
286N/A * @see org.w3c.dom.TypeInfo#getTypeNamespace()
286N/A */
286N/A public String getTypeNamespace() {
286N/A return null;
286N/A }
286N/A
286N/A /**
286N/A * Introduced in DOM Level 3. <p>
286N/A * Checks if a type is derived from another by restriction. See:
286N/A * http://www.w3.org/TR/DOM-Level-3-Core/core.html#TypeInfo-isDerivedFrom
286N/A *
286N/A * @param ancestorNS
286N/A * The namspace of the ancestor type declaration
286N/A * @param ancestorName
286N/A * The name of the ancestor type declaration
286N/A * @param type
286N/A * The reference type definition
286N/A *
286N/A * @return boolean True if the type is derived by restriciton for the
286N/A * reference type
286N/A */
286N/A public boolean isDerivedFrom(String typeNamespaceArg,
286N/A String typeNameArg,
286N/A int derivationMethod) {
286N/A
286N/A return false;
286N/A }
286N/A
286N/A /**
286N/A * Method getSchemaTypeInfo.
286N/A * @return TypeInfo
286N/A */
286N/A public TypeInfo getSchemaTypeInfo(){
286N/A if(needsSyncData()) {
286N/A synchronizeData();
286N/A }
286N/A return this;
286N/A }
286N/A
286N/A //
286N/A // Public methods
286N/A //
286N/A
286N/A /**
286N/A * NON-DOM: Subclassed to flip the attributes' readonly switch as well.
286N/A * @see NodeImpl#setReadOnly
286N/A */
286N/A public void setReadOnly(boolean readOnly, boolean deep) {
286N/A super.setReadOnly(readOnly,deep);
286N/A if (attributes != null) {
286N/A attributes.setReadOnly(readOnly,true);
286N/A }
286N/A }
286N/A
286N/A
286N/A
286N/A //
286N/A // Protected methods
286N/A //
286N/A
286N/A /** Synchronizes the data (name and value) for fast nodes. */
286N/A protected void synchronizeData() {
286N/A
286N/A // no need to sync in the future
286N/A needsSyncData(false);
286N/A
286N/A // we don't want to generate any event for this so turn them off
286N/A boolean orig = ownerDocument.getMutationEvents();
286N/A ownerDocument.setMutationEvents(false);
286N/A
286N/A // attributes
286N/A setupDefaultAttributes();
286N/A
286N/A // set mutation events flag back to its original value
286N/A ownerDocument.setMutationEvents(orig);
286N/A
286N/A } // synchronizeData()
286N/A
286N/A // support for DOM Level 3 renameNode method
286N/A // @param el The element from which to take the attributes
286N/A void moveSpecifiedAttributes(ElementImpl el) {
286N/A if (needsSyncData()) {
286N/A synchronizeData();
286N/A }
286N/A if (el.hasAttributes()) {
286N/A if (attributes == null) {
286N/A attributes = new AttributeMap(this, null);
286N/A }
286N/A attributes.moveSpecifiedAttributes(el.attributes);
286N/A }
286N/A }
286N/A
286N/A /** Setup the default attributes. */
286N/A protected void setupDefaultAttributes() {
286N/A NamedNodeMapImpl defaults = getDefaultAttributes();
286N/A if (defaults != null) {
286N/A attributes = new AttributeMap(this, defaults);
286N/A }
286N/A }
286N/A
286N/A /** Reconcile default attributes. */
286N/A protected void reconcileDefaultAttributes() {
286N/A if (attributes != null) {
286N/A NamedNodeMapImpl defaults = getDefaultAttributes();
286N/A attributes.reconcileDefaults(defaults);
286N/A }
286N/A }
286N/A
286N/A /** Get the default attributes. */
286N/A protected NamedNodeMapImpl getDefaultAttributes() {
286N/A
286N/A DocumentTypeImpl doctype =
286N/A (DocumentTypeImpl) ownerDocument.getDoctype();
286N/A if (doctype == null) {
286N/A return null;
286N/A }
286N/A ElementDefinitionImpl eldef =
286N/A (ElementDefinitionImpl)doctype.getElements()
286N/A .getNamedItem(getNodeName());
286N/A if (eldef == null) {
286N/A return null;
286N/A }
286N/A return (NamedNodeMapImpl) eldef.getAttributes();
286N/A
286N/A } // getDefaultAttributes()
286N/A
286N/A} // class ElementImpl