blob: c9136964f32b58b52193520d70109108f6b016bc [file] [log] [blame]
/*
* 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.2 1999/11/30 21:16:25 roddey
* Changes to add the transcode() method to DOMString, which returns a transcoded
* version (to local code page) of the DOM string contents. And I changed all of the
* exception 'throw by pointer' to 'throw by value' style.
*
* Revision 1.1.1.1 1999/11/09 01:09:08 twl
* Initial checkin
*
* 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 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 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 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 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 DOM_DOMException(
DOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, null);
if (!(newAttr->isAttrImpl()))
throw 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 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 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 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 DOM_DOMException(
DOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, null);
if (newAttr -> getOwnerDocument() != this -> getOwnerDocument())
throw 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);
}