| /* |
| * The Apache Software License, Version 1.1 |
| * |
| * Copyright (c) 1999 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.ibm.com . For more information |
| * on the Apache Software Foundation, please see |
| * <http://www.apache.org/>. |
| */ |
| |
| /** |
| * $Log$ |
| * Revision 1.1 1999/11/09 01:09:08 twl |
| * Initial revision |
| * |
| * Revision 1.3 1999/11/08 20:44:26 rahul |
| * Swat for adding in Product name and CVS comment log variable. |
| * |
| */ |
| |
| #include "DeepNodeListImpl.hpp" |
| #include "DocumentImpl.hpp" |
| #include "DocumentTypeImpl.hpp" |
| #include "DOM_DOMException.hpp" |
| #include "DStringPool.hpp" |
| #include "ElementImpl.hpp" |
| #include "ElementDefinitionImpl.hpp" |
| #include "NamedNodeMapImpl.hpp" |
| #include "NodeVector.hpp" |
| #include "TextImpl.hpp" |
| |
| |
| ElementImpl::ElementImpl(DocumentImpl *ownerDoc, const DOMString &nam) : |
| NodeImpl(ownerDoc, nam, DOM_Node::ELEMENT_NODE, false, null) |
| { |
| |
| // If there is an ElementDefintion, set its Attributes up as |
| // shadows behind our own. |
| NamedNodeMapImpl *defaultAttrs = null; |
| DocumentTypeImpl *doctype = (DocumentTypeImpl *) ownerDocument->getDoctype(); |
| if (doctype != null) |
| { |
| ElementDefinitionImpl *eldef=(ElementDefinitionImpl *) |
| doctype->getElements()->getNamedItem(this->name); |
| if(eldef!=null) |
| defaultAttrs=(NamedNodeMapImpl *)eldef->getAttributes(); |
| } |
| attributes = new NamedNodeMapImpl(ownerDoc,defaultAttrs); |
| }; |
| |
| //DOM Level 2 |
| ElementImpl::ElementImpl(DocumentImpl *ownerDoc, |
| const DOMString &namespaceURI, const DOMString &qualifiedName) : |
| NodeImpl(ownerDoc, namespaceURI, qualifiedName, DOM_Node::ELEMENT_NODE, false, null) |
| { |
| |
| // If there is an ElementDefintion, set its Attributes up as |
| // shadows behind our own. |
| NamedNodeMapImpl *defaultAttrs = null; |
| DocumentTypeImpl *doctype = (DocumentTypeImpl *) ownerDocument->getDoctype(); |
| if (doctype != null) |
| { |
| ElementDefinitionImpl *eldef=(ElementDefinitionImpl *) |
| doctype->getElements()->getNamedItem(this->name); |
| if(eldef!=null) |
| defaultAttrs=(NamedNodeMapImpl *)eldef->getAttributes(); |
| } |
| attributes = new NamedNodeMapImpl(ownerDoc,defaultAttrs); |
| } |
| |
| |
| ElementImpl::ElementImpl(const ElementImpl &other, bool deep) |
| : NodeImpl(other, deep) |
| { |
| attributes = other.attributes->cloneMap(); |
| }; |
| |
| |
| ElementImpl::~ElementImpl() |
| { |
| if (attributes) |
| { |
| attributes->removeAll(); |
| NamedNodeMapImpl::removeRef(attributes); |
| } |
| }; |
| |
| |
| NodeImpl *ElementImpl::cloneNode(bool deep) |
| { |
| return new ElementImpl(*this, deep); |
| }; |
| |
| |
| DOMString ElementImpl::getAttribute(const DOMString &nam) |
| { |
| static DOMString *emptyString = 0; |
| AttrImpl * attr=(AttrImpl *)(attributes->getNamedItem(nam)); |
| return (attr==null) ? DStringPool::getStaticString("", &emptyString) : attr->getValue(); |
| }; |
| |
| |
| |
| AttrImpl *ElementImpl::getAttributeNode(const DOMString &nam) |
| { |
| return (AttrImpl *)(attributes->getNamedItem(nam)); |
| }; |
| |
| |
| NamedNodeMapImpl *ElementImpl::getAttributes() |
| { |
| return attributes; |
| }; |
| |
| |
| |
| DeepNodeListImpl *ElementImpl::getElementsByTagName(const DOMString &tagname) |
| { |
| return new DeepNodeListImpl(this,tagname); |
| }; |
| |
| |
| DOMString ElementImpl::getTagName() |
| { |
| return name; |
| } |
| |
| |
| bool ElementImpl::isElementImpl() |
| { |
| return true; |
| }; |
| |
| |
| void ElementImpl::normalize() |
| { |
| NodeImpl *kid, *next; |
| for (kid = getFirstChild(); kid != null; kid = next) |
| { |
| next = kid->getNextSibling(); |
| |
| // If kid and next are both Text nodes (but _not_ CDATASection, |
| // which is a subclass of Text), they can be merged. |
| if (next != null && |
| kid->isTextImpl() && !(kid->isCDATASectionImpl()) && |
| next->isTextImpl() && !(next->isCDATASectionImpl()) ) |
| { |
| ((TextImpl *) kid)->appendData(((TextImpl *) next)->getData()); |
| removeChild(next); |
| if (next->nodeRefCount == 0) |
| deleteIf(next); |
| next = kid; // Don't advance; there might be another. |
| } |
| |
| // Otherwise it might be an Element, which is handled recursively |
| else |
| if (kid->isElementImpl()) |
| ((ElementImpl *) kid)->normalize(); |
| }; |
| |
| // changed() will have occurred when the removeChild() was done, |
| // so does not have to be reissued. |
| }; |
| |
| |
| void ElementImpl::removeAttribute(const DOMString &nam) |
| { |
| if (readOnly) |
| throw new DOM_DOMException( |
| DOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, null); |
| |
| AttrImpl *att = (AttrImpl *) attributes->getNamedItem(nam); |
| // Remove it (and let the NamedNodeMap recreate the default, if any) |
| if (att != null) |
| { |
| attributes->removeNamedItem(nam); |
| att->setOwnerElement(null); //DOM Level 2 |
| if (att->nodeRefCount == 0) |
| NodeImpl::deleteIf(att); |
| } |
| }; |
| |
| |
| |
| AttrImpl *ElementImpl::removeAttributeNode(AttrImpl *oldAttr) |
| { |
| if (readOnly) |
| throw new DOM_DOMException( |
| DOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, null); |
| |
| AttrImpl *found = (AttrImpl *) attributes->getNamedItem(oldAttr->getName()); |
| |
| // If it is in fact the right object, remove it (and let the |
| // NamedNodeMap recreate the default, if any) |
| |
| if (found == oldAttr) |
| { |
| attributes->removeNamedItem(oldAttr->getName()); |
| found->setOwnerElement(null); //DOM Level 2 |
| return found; |
| } |
| else |
| throw new DOM_DOMException(DOM_DOMException::NOT_FOUND_ERR, null); |
| return null; // just to keep the compiler happy |
| }; |
| |
| |
| |
| void ElementImpl::setAttribute(const DOMString &nam, const DOMString &val) |
| { |
| if (readOnly) |
| throw new DOM_DOMException( |
| DOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, null); |
| |
| AttrImpl *newAttr = (AttrImpl *) ownerDocument->createAttribute(nam); |
| newAttr->setNodeValue(val); |
| newAttr->setOwnerElement(this); //DOM Level 2 |
| AttrImpl *oldAttr = (AttrImpl *)attributes->setNamedItem(newAttr); |
| |
| if (oldAttr) { |
| oldAttr->setOwnerElement(null); //DOM Level 2 |
| if (oldAttr->nodeRefCount == 0) |
| NodeImpl::deleteIf(oldAttr); |
| } |
| }; |
| |
| |
| |
| AttrImpl * ElementImpl::setAttributeNode(AttrImpl *newAttr) |
| { |
| if (readOnly) |
| throw new DOM_DOMException( |
| DOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, null); |
| |
| if (!(newAttr->isAttrImpl())) |
| throw new DOM_DOMException(DOM_DOMException::WRONG_DOCUMENT_ERR, null); |
| AttrImpl *oldAttr = (AttrImpl *) attributes->getNamedItem(newAttr->getName()); |
| if (oldAttr) |
| oldAttr->setOwnerElement(null); //DOM Level 2 |
| |
| // This will throw INUSE if necessary |
| attributes->setNamedItem(newAttr); |
| |
| // Attr node reference counting note: |
| // If oldAttr's refcount is zero at this point, here's what happens... |
| // |
| // oldAttr is returned from this function to DOM_Attr::setAttributeNode, |
| // which wraps a DOM_Attr around the returned pointer and sends it |
| // up to application code, incrementing the reference count in the process. |
| // When the app DOM_Attr's destructor runs, the reference count is |
| // decremented back to zero and oldAttr will be deleted at that time. |
| |
| return oldAttr; |
| }; |
| |
| |
| void ElementImpl::setNodeValue(const DOMString &x) |
| { |
| throw new DOM_DOMException(DOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, null); |
| }; |
| |
| |
| |
| void ElementImpl::setReadOnly(bool readOnl, bool deep) |
| { |
| NodeImpl::setReadOnly(readOnl,deep); |
| attributes->setReadOnly(readOnl,true); |
| }; |
| |
| |
| //Introduced in DOM Level 2 |
| DOMString ElementImpl::getAttributeNS(const DOMString &namespaceURI, |
| const DOMString &localName) |
| { |
| if (namespaceURI == null || namespaceURI.length() == 0) |
| return getAttribute(localName); |
| static DOMString *emptyString = 0; |
| AttrImpl * attr=(AttrImpl *)(attributes->getNamedItemNS(namespaceURI, localName)); |
| return (attr==null) ? DStringPool::getStaticString("", &emptyString) : attr->getValue(); |
| } |
| |
| |
| void ElementImpl::setAttributeNS(const DOMString &namespaceURI, |
| const DOMString &qualifiedName, const DOMString &value) |
| { |
| if (namespaceURI == null || namespaceURI.length() == 0) { |
| setAttribute(qualifiedName, value); |
| return; |
| } |
| if (readOnly) |
| throw new DOM_DOMException( |
| DOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, null); |
| |
| AttrImpl *newAttr = (AttrImpl *) ownerDocument->createAttributeNS(namespaceURI, qualifiedName); |
| newAttr->setNodeValue(value); |
| newAttr->setOwnerElement(this); |
| AttrImpl *oldAttr = (AttrImpl *)attributes->setNamedItem(newAttr); |
| |
| if (oldAttr) { |
| oldAttr->setOwnerElement(null); |
| if (oldAttr->nodeRefCount == 0) |
| NodeImpl::deleteIf(oldAttr); |
| } |
| } |
| |
| |
| void ElementImpl::removeAttributeNS(const DOMString &namespaceURI, |
| const DOMString &localName) |
| { |
| if (namespaceURI == null || namespaceURI.length() == 0) { |
| removeAttribute(localName); |
| return; |
| } |
| if (readOnly) |
| throw new DOM_DOMException( |
| DOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, null); |
| |
| AttrImpl *att = (AttrImpl *) attributes->getNamedItemNS(namespaceURI, localName); |
| // Remove it (and let the NamedNodeMap recreate the default, if any) |
| if (att != null) { |
| attributes->removeNamedItemNS(namespaceURI, localName); |
| att->setOwnerElement(null); |
| if (att->nodeRefCount == 0) |
| NodeImpl::deleteIf(att); |
| } |
| } |
| |
| |
| AttrImpl *ElementImpl::getAttributeNodeNS(const DOMString &namespaceURI, |
| const DOMString &localName) |
| { |
| if (namespaceURI == null || namespaceURI.length() == 0) |
| return getAttributeNode(localName); |
| return (AttrImpl *)(attributes->getNamedItemNS(namespaceURI, localName)); |
| } |
| |
| |
| AttrImpl *ElementImpl::setAttributeNodeNS(AttrImpl *newAttr) |
| { |
| if (newAttr && newAttr ->getNamespaceURI() == null) |
| return setAttributeNode(newAttr); |
| if (readOnly) |
| throw new DOM_DOMException( |
| DOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, null); |
| |
| if (newAttr -> getOwnerDocument() != this -> getOwnerDocument()) |
| throw new DOM_DOMException(DOM_DOMException::WRONG_DOCUMENT_ERR, null); |
| AttrImpl *oldAttr = (AttrImpl *) attributes->getNamedItemNS( |
| newAttr->getNamespaceURI(), newAttr->getLocalName()); |
| if (oldAttr) |
| oldAttr->setOwnerElement(null); |
| |
| // This will throw INUSE if necessary |
| attributes->setNamedItem(newAttr); |
| |
| // Attr node reference counting note: |
| // If oldAttr's refcount is zero at this point, here's what happens... |
| // |
| // oldAttr is returned from this function to DOM_Attr::setAttributeNode, |
| // which wraps a DOM_Attr around the returned pointer and sends it |
| // up to application code, incrementing the reference count in the process. |
| // When the app DOM_Attr's destructor runs, the reference count is |
| // decremented back to zero and oldAttr will be deleted at that time. |
| |
| return oldAttr; |
| } |
| |
| |
| DeepNodeListImpl *ElementImpl::getElementsByTagNameNS(const DOMString &namespaceURI, |
| const DOMString &localName) |
| { |
| return new DeepNodeListImpl(this,namespaceURI, localName); |
| } |
| |