diff --git a/src/xercesc/dom/DOMDocument.hpp b/src/xercesc/dom/DOMDocument.hpp index eaefd189b62a005ef928a0992cf4e49212647704..f28567b6de9258fd617214f9148e1c53700f54a3 100644 --- a/src/xercesc/dom/DOMDocument.hpp +++ b/src/xercesc/dom/DOMDocument.hpp @@ -652,6 +652,54 @@ public: * @since DOM Level 3 */ virtual void setDocumentURI(const XMLCh* documentURI) = 0; + + /** + * Rename an existing node. When possible this simply changes the name of + * the given node, otherwise this creates a new node with the specified + * name and replaces the existing node with the new node as described + * below. This only applies to nodes of type <code>ELEMENT_NODE</code> + * and <code>ATTRIBUTE_NODE</code>. + * <br>When a new node is created, the following operations are performed: + * the new node is created, any registered event listener is registered + * on the new node, any user data attached to the old node is removed + * from that node, the old node is removed from its parent if it has + * one, the children are moved to the new node, if the renamed node is + * an <code>DOMElement</code> its attributes are moved to the new node, the + * new node is inserted at the position the old node used to have in its + * parent's child nodes list if it has one, the user data that was + * attached to the old node is attach to the new node, the user data + * event <code>NODE_RENAMED</code> is fired. + * <br>When the node being renamed is an <code>DOMAttr</code> that is + * attached to an <code>DOMElement</code>, the node is first removed from + * the <code>DOMElement</code> attributes map. Then, once renamed, either + * by modifying the existing node or creating a new one as described + * above, it is put back. + * + * <p><b>"Experimental - subject to change"</b></p> + * + * @param n The node to rename. + * @param namespaceURI The new namespaceURI. + * @param name The new qualified name. + * @return The renamed node. This is either the specified node or the new + * node that was created to replace the specified node. + * @exception DOMException + * NOT_SUPPORTED_ERR: Raised when the type of the specified node is + * neither <code>ELEMENT_NODE</code> nor <code>ATTRIBUTE_NODE</code>. + * <br>WRONG_DOCUMENT_ERR: Raised when the specified node was created + * from a different document than this document. + * <br>NAMESPACE_ERR: Raised if the <code>qualifiedName</code> is + * malformed per the Namespaces in XML specification, if the + * <code>qualifiedName</code> has a prefix and the + * <code>namespaceURI</code> is <code>null</code>, or if the + * <code>qualifiedName</code> has a prefix that is "xml" and the + * <code>namespaceURI</code> is different from " + * http://www.w3.org/XML/1998/namespace" . Also raised, when the node + * being renamed is an attribute, if the <code>qualifiedName</code>, + * or its prefix, is "xmlns" and the <code>namespaceURI</code> is + * different from "http://www.w3.org/2000/xmlns/". + * @since DOM Level 3 + */ + virtual DOMNode* renameNode(DOMNode* n, const XMLCh* namespaceURI, const XMLCh* name) = 0; //@} // ----------------------------------------------------------------------- diff --git a/src/xercesc/dom/impl/DOMAttrImpl.cpp b/src/xercesc/dom/impl/DOMAttrImpl.cpp index e73afe85e482ac62886d64c5a7943d7eb7fc4d2e..610a554fe438371c03c40d2b8d01d95438b2e301 100644 --- a/src/xercesc/dom/impl/DOMAttrImpl.cpp +++ b/src/xercesc/dom/impl/DOMAttrImpl.cpp @@ -241,6 +241,9 @@ void DOMAttrImpl::setOwnerElement(DOMElement *ownerElem) fNode.isOwned(false); } + +//For DOM Level 3 + void DOMAttrImpl::release() { if (fNode.isOwned() && !fNode.isToBeReleased()) @@ -258,6 +261,50 @@ void DOMAttrImpl::release() } +DOMNode* DOMAttrImpl::rename(const XMLCh* namespaceURI, const XMLCh* name) +{ + DOMElement* el = getOwnerElement(); + DOMDocumentImpl* doc = (DOMDocumentImpl*) getOwnerDocument(); + + if (el) + el->removeAttributeNode(this); + + if (!namespaceURI || !*namespaceURI) { + fName = doc->getPooledString(name); + + if (el) + el->setAttributeNode(this); + + return this; + } + else { + + // create a new AttrNS + DOMAttr* newAttr = doc->createAttributeNS(namespaceURI, name); + + // transfer the userData + doc->transferUserData(castToNodeImpl(this), castToNodeImpl(newAttr)); + + // move children to new node + DOMNode* child = getFirstChild(); + while (child) { + removeChild(child); + newAttr->appendChild(child); + child = getFirstChild(); + } + + // and fire user data NODE_RENAMED event + castToNodeImpl(newAttr)->callUserDataHandlers(DOMUserDataHandler::NODE_RENAMED, this, newAttr); + + // reattach attr to element + if (el) + el->setAttributeNodeNS(newAttr); + + return newAttr; + } +} + + DOMNode* DOMAttrImpl::appendChild(DOMNode *newChild) {return fParent.appendChild (newChild); }; DOMNamedNodeMap* DOMAttrImpl::getAttributes() const {return fNode.getAttributes (); }; DOMNodeList* DOMAttrImpl::getChildNodes() const {return fParent.getChildNodes (); }; diff --git a/src/xercesc/dom/impl/DOMAttrImpl.hpp b/src/xercesc/dom/impl/DOMAttrImpl.hpp index 06f2cb5afc2ee229c8c12dd88b4e813fa90a6d7e..4ee9a0ec31d4f3fdf2092c1e1bafe3456a5803ff 100644 --- a/src/xercesc/dom/impl/DOMAttrImpl.hpp +++ b/src/xercesc/dom/impl/DOMAttrImpl.hpp @@ -103,6 +103,9 @@ public: //Introduced in DOM Level 2 DOMElement *getOwnerElement() const; void setOwnerElement(DOMElement *ownerElem); //internal use only + + // helper function for DOM Level 3 renameNode + virtual DOMNode* rename(const XMLCh* namespaceURI, const XMLCh* name); }; #endif diff --git a/src/xercesc/dom/impl/DOMAttrNSImpl.cpp b/src/xercesc/dom/impl/DOMAttrNSImpl.cpp index fd0f44efd219480e587074c6e186cdba4f76ff70..bf52cd52090d104d2bf0c9bbfd669c66f5dcf96d 100644 --- a/src/xercesc/dom/impl/DOMAttrNSImpl.cpp +++ b/src/xercesc/dom/impl/DOMAttrNSImpl.cpp @@ -62,6 +62,7 @@ #include "DOMAttrNSImpl.hpp" #include "DOMDocumentImpl.hpp" #include <xercesc/dom/DOMDocument.hpp> +#include <xercesc/dom/DOMElement.hpp> #include <xercesc/dom/DOMException.hpp> #include "assert.h" @@ -80,44 +81,8 @@ DOMAttrNSImpl::DOMAttrNSImpl(DOMDocument *ownerDoc, const XMLCh *qualifiedName) : DOMAttrImpl(ownerDoc, qualifiedName) { - const XMLCh * xmlns = DOMNodeImpl::getXmlnsString(); - const XMLCh * xmlnsURI = DOMNodeImpl::getXmlnsURIString(); - this->fName = ((DOMDocumentImpl *)ownerDoc)->getPooledString(qualifiedName); - - int index = DOMDocumentImpl::indexofQualifiedName(qualifiedName); - if (index < 0) - throw DOMException(DOMException::NAMESPACE_ERR, 0); - - bool xmlnsAlone = false; //true if attribute name is "xmlns" - if (index == 0) { //qualifiedName contains no ':' - if (XMLString::compareString(this->fName, xmlns) == 0) { - if (XMLString::compareString(namespaceURI, xmlnsURI) != 0) - throw DOMException(DOMException::NAMESPACE_ERR, 0); - xmlnsAlone = true; - } - this -> fPrefix = 0; - this -> fLocalName = this -> fName; - } else { //0 < index < this->name.length()-1 - XMLCh* newName; - XMLCh temp[4000]; - if (index >= 3999) - newName = new XMLCh[XMLString::stringLen(qualifiedName)+1]; - else - newName = temp; - - XMLString::copyNString(newName, fName, index); - newName[index] = chNull; - this-> fPrefix = ((DOMDocumentImpl *)ownerDoc)->getPooledString(newName); - this -> fLocalName = ((DOMDocumentImpl *)ownerDoc)->getPooledString(fName+index+1); - - if (index >= 3999) - delete[] newName; - } - - const XMLCh * URI = xmlnsAlone ? - xmlnsURI : DOMNodeImpl::mapPrefix(fPrefix, namespaceURI, DOMNode::ATTRIBUTE_NODE); - this -> fNamespaceURI = (URI == 0) ? 0 : ((DOMDocumentImpl *)ownerDoc)->getPooledString(URI); -}; + setName(namespaceURI, qualifiedName); +} DOMAttrNSImpl::DOMAttrNSImpl(const DOMAttrNSImpl &other, bool deep) : DOMAttrImpl(other, deep) @@ -221,3 +186,60 @@ void DOMAttrNSImpl::release() } } + +DOMNode* DOMAttrNSImpl::rename(const XMLCh* namespaceURI, const XMLCh* name) +{ + DOMElement* el = getOwnerElement(); + if (el) + el->removeAttributeNode(this); + + setName(namespaceURI, name); + + if (el) + el->setAttributeNodeNS(this); + + return this; +} + +void DOMAttrNSImpl::setName(const XMLCh* namespaceURI, const XMLCh* qualifiedName) +{ + DOMDocumentImpl* ownerDoc = (DOMDocumentImpl *) getOwnerDocument(); + const XMLCh * xmlns = DOMNodeImpl::getXmlnsString(); + const XMLCh * xmlnsURI = DOMNodeImpl::getXmlnsURIString(); + this->fName = ownerDoc->getPooledString(qualifiedName); + + int index = DOMDocumentImpl::indexofQualifiedName(qualifiedName); + if (index < 0) + throw DOMException(DOMException::NAMESPACE_ERR, 0); + + bool xmlnsAlone = false; //true if attribute name is "xmlns" + if (index == 0) { //qualifiedName contains no ':' + if (XMLString::compareString(this->fName, xmlns) == 0) { + if (XMLString::compareString(namespaceURI, xmlnsURI) != 0) + throw DOMException(DOMException::NAMESPACE_ERR, 0); + xmlnsAlone = true; + } + this -> fPrefix = 0; + this -> fLocalName = this -> fName; + } else { //0 < index < this->name.length()-1 + XMLCh* newName; + XMLCh temp[4000]; + if (index >= 3999) + newName = new XMLCh[XMLString::stringLen(qualifiedName)+1]; + else + newName = temp; + + XMLString::copyNString(newName, fName, index); + newName[index] = chNull; + this-> fPrefix = ownerDoc->getPooledString(newName); + this -> fLocalName = ownerDoc->getPooledString(fName+index+1); + + if (index >= 3999) + delete[] newName; + } + + const XMLCh * URI = xmlnsAlone ? + xmlnsURI : DOMNodeImpl::mapPrefix(fPrefix, namespaceURI, DOMNode::ATTRIBUTE_NODE); + this -> fNamespaceURI = (URI == 0) ? 0 : ownerDoc->getPooledString(URI); +}; + diff --git a/src/xercesc/dom/impl/DOMAttrNSImpl.hpp b/src/xercesc/dom/impl/DOMAttrNSImpl.hpp index 8d75e8fee4f2e9ca6e3c6fe473c04ca23270646f..838c5ca2a7fb108fcae4a6bc41bb9b61275d1124 100644 --- a/src/xercesc/dom/impl/DOMAttrNSImpl.hpp +++ b/src/xercesc/dom/impl/DOMAttrNSImpl.hpp @@ -95,6 +95,10 @@ public: virtual const XMLCh * getLocalName() const; virtual void setPrefix(const XMLCh *prefix); virtual void release(); + + // helper function for DOM Level 3 renameNode + virtual DOMNode* rename(const XMLCh* namespaceURI, const XMLCh* name); + void setName(const XMLCh* namespaceURI, const XMLCh* name); }; #endif diff --git a/src/xercesc/dom/impl/DOMDocumentImpl.cpp b/src/xercesc/dom/impl/DOMDocumentImpl.cpp index 4996a22933123c0d199a30c8f0d8705399e8b07d..4a25e2a46165105892099e15d20abc394f940c78 100644 --- a/src/xercesc/dom/impl/DOMDocumentImpl.cpp +++ b/src/xercesc/dom/impl/DOMDocumentImpl.cpp @@ -1109,6 +1109,33 @@ void DOMDocumentImpl::callUserDataHandlers(const DOMNodeImpl* n, DOMUserDataHand } +void DOMDocumentImpl::transferUserData(DOMNodeImpl* n1, DOMNodeImpl* n2) +{ + if (fUserDataTable) { + fUserDataTable->transferElement((void*)n1, (void*)n2); + n1->hasUserData(false); + n2->hasUserData(true); + } +} + + +DOMNode* DOMDocumentImpl::renameNode(DOMNode* n, const XMLCh* namespaceURI, const XMLCh* name) +{ + if (n->getOwnerDocument() != this) + throw DOMException(DOMException::WRONG_DOCUMENT_ERR, 0); + + switch (n->getNodeType()) { + case ELEMENT_NODE: + return ((DOMElementImpl*)n)->rename(namespaceURI, name); + case ATTRIBUTE_NODE: + return ((DOMAttrImpl*)n)->rename(namespaceURI, name); + default: + throw DOMException(DOMException::NOT_SUPPORTED_ERR, 0); + } + + return 0; +} + void DOMDocumentImpl::release() { DOMDocument* doc = (DOMDocument*) this; diff --git a/src/xercesc/dom/impl/DOMDocumentImpl.hpp b/src/xercesc/dom/impl/DOMDocumentImpl.hpp index b52171221c732f8f282df90663899ea72309707b..e2c6ff597770022cd2dfc7bc700e37143b927313 100644 --- a/src/xercesc/dom/impl/DOMDocumentImpl.hpp +++ b/src/xercesc/dom/impl/DOMDocumentImpl.hpp @@ -319,6 +319,11 @@ public: DOMUserDataHandler::DOMOperationType operation, const DOMNode* src, const DOMNode* dst) const; + void transferUserData(DOMNodeImpl* n1, DOMNodeImpl* n2); + + DOMNode* renameNode(DOMNode* n, + const XMLCh* namespaceURI, + const XMLCh* name); //Return the index > 0 of ':' in the given qualified name qName="prefix:localName". //Return 0 if there is no ':', or -1 if qName is malformed such as ":abcd". diff --git a/src/xercesc/dom/impl/DOMElementImpl.cpp b/src/xercesc/dom/impl/DOMElementImpl.cpp index 8201a239c455a601126fa9cfe7a02e2dddf5d715..0f107349014aca515481bbbbb4cd343b0b519fa2 100644 --- a/src/xercesc/dom/impl/DOMElementImpl.cpp +++ b/src/xercesc/dom/impl/DOMElementImpl.cpp @@ -68,6 +68,8 @@ #include "DOMDocumentImpl.hpp" #include "DOMParentNode.hpp" #include "DOMStringPool.hpp" +#include "DOMCasts.hpp" +#include "DOMElementNSImpl.hpp" #include "DOMDeepNodeListImpl.hpp" @@ -185,10 +187,10 @@ void DOMElementImpl::removeAttribute(const XMLCh *nam) throw DOMException( DOMException::NO_MODIFICATION_ALLOWED_ERR, 0); - DOMNode *att = fAttributes->getNamedItem(nam); - if (att != 0) + XMLSize_t i = fAttributes->findNamePoint(nam); + if (i >= 0) { - fAttributes->removeNamedItem(nam); + DOMNode *att = fAttributes->removeNamedItemAt(i); att->release(); } }; @@ -201,17 +203,29 @@ DOMAttr *DOMElementImpl::removeAttributeNode(DOMAttr *oldAttr) throw DOMException( DOMException::NO_MODIFICATION_ALLOWED_ERR, 0); - DOMNode *found = fAttributes->getNamedItem(oldAttr->getName()); + DOMNode* found = 0; - // If it is in fact the right object, remove it. + // Since there is no removeAttributeNodeNS, check if this oldAttr has NS or not + const XMLCh* localName = oldAttr->getLocalName(); + XMLSize_t i = 0; + if (localName) + i = fAttributes->findNamePoint(oldAttr->getNamespaceURI(), localName); + else + i = fAttributes->findNamePoint(oldAttr->getName()); + + if (i >= 0) { + // If it is in fact the right object, remove it. + found = fAttributes->item(i); + if (found == oldAttr) + fAttributes->removeNamedItemAt(i); + else + throw DOMException(DOMException::NOT_FOUND_ERR, 0); - if (found == oldAttr) - fAttributes->removeNamedItem(oldAttr->getName()); + } else throw DOMException(DOMException::NOT_FOUND_ERR, 0); - return (DOMAttr *)found; - + return (DOMAttr *)found; }; @@ -300,11 +314,10 @@ void DOMElementImpl::removeAttributeNS(const XMLCh *fNamespaceURI, throw DOMException( DOMException::NO_MODIFICATION_ALLOWED_ERR, 0); - DOMAttr *att = - (DOMAttr *)fAttributes->getNamedItemNS(fNamespaceURI, fLocalName); - // Remove it - if (att != 0) { - fAttributes->removeNamedItemNS(fNamespaceURI, fLocalName); + XMLSize_t i = fAttributes->findNamePoint(fNamespaceURI, fLocalName); + if (i >= 0) + { + DOMNode *att = fAttributes->removeNamedItemAt(i); att->release(); } } @@ -476,3 +489,52 @@ bool DOMElementImpl::isEqualNode(const DOMNode* arg) return fParent.isEqualNode(arg); }; + +DOMNode* DOMElementImpl::rename(const XMLCh* namespaceURI, const XMLCh* name) +{ + DOMDocumentImpl* doc = (DOMDocumentImpl*) getOwnerDocument(); + + if (!namespaceURI || !*namespaceURI) { + fName = doc->fNamePool->getPooledString(name); + fAttributes->reconcileDefaultAttributes(getDefaultAttributes()); + + return this; + } + else { + + // create a new ElementNS + DOMElementNSImpl* newElem = (DOMElementNSImpl*)doc->createElementNS(namespaceURI, name); + + // transfer the userData + doc->transferUserData(castToNodeImpl(this), castToNodeImpl(newElem)); + + // remove old node from parent if any + DOMNode* parent = getParentNode(); + DOMNode* nextSib = getNextSibling(); + if (parent) { + parent->removeChild(this); + } + + // move children to new node + DOMNode* child = getFirstChild(); + while (child) { + removeChild(child); + newElem->appendChild(child); + child = getFirstChild(); + } + + // insert new node where old one was + if (parent) { + parent->insertBefore(newElem, nextSib); + } + + // move specified attributes to new node + newElem->fAttributes->moveSpecifiedAttributes(fAttributes); + + // and fire user data NODE_RENAMED event + castToNodeImpl(newElem)->callUserDataHandlers(DOMUserDataHandler::NODE_RENAMED, this, newElem); + + return newElem; + } +} + diff --git a/src/xercesc/dom/impl/DOMElementImpl.hpp b/src/xercesc/dom/impl/DOMElementImpl.hpp index 10c5bdbe3993065869fea95f39666e3c2bbfa370..a427bb2b191fe9ea3685b2e633de7af953d8be9e 100644 --- a/src/xercesc/dom/impl/DOMElementImpl.hpp +++ b/src/xercesc/dom/impl/DOMElementImpl.hpp @@ -138,7 +138,8 @@ public: virtual DOMAttrMapImpl *getDefaultAttributes(); virtual void setupDefaultAttributes(); - + // helper function for DOM Level 3 renameNode + virtual DOMNode* rename(const XMLCh* namespaceURI, const XMLCh* name); }; #endif diff --git a/src/xercesc/dom/impl/DOMElementNSImpl.cpp b/src/xercesc/dom/impl/DOMElementNSImpl.cpp index 9aea634758a775a91d3708c983835602f2e9b841..f9ca4ce09b5e722783756f7d3ae45c896d08ef8d 100644 --- a/src/xercesc/dom/impl/DOMElementNSImpl.cpp +++ b/src/xercesc/dom/impl/DOMElementNSImpl.cpp @@ -77,35 +77,8 @@ DOMElementNSImpl::DOMElementNSImpl(DOMDocument *ownerDoc, const XMLCh *qualifiedName) : DOMElementImpl(ownerDoc, qualifiedName) { - this->fName = ((DOMDocumentImpl *)ownerDoc)->getPooledString(qualifiedName); - - int index = DOMDocumentImpl::indexofQualifiedName(qualifiedName); - if (index < 0) - throw DOMException(DOMException::NAMESPACE_ERR, 0); - - if (index == 0) { //qualifiedName contains no ':' - this -> fPrefix = 0; - this -> fLocalName = this -> fName; - } else { //0 < index < this->name.length()-1 - XMLCh* newName; - XMLCh temp[4000]; - if (index >= 3999) - newName = new XMLCh[XMLString::stringLen(qualifiedName)+1]; - else - newName = temp; - - XMLString::copyNString(newName, fName, index); - newName[index] = chNull; - this-> fPrefix = ((DOMDocumentImpl *)ownerDoc)->getPooledString(newName); - this -> fLocalName = ((DOMDocumentImpl *)ownerDoc)->getPooledString(fName+index+1); - - if (index >= 3999) - delete[] newName; - } - - const XMLCh * URI = DOMNodeImpl::mapPrefix(fPrefix, namespaceURI, DOMNode::ELEMENT_NODE); - this -> fNamespaceURI = (URI == 0) ? 0 : ((DOMDocumentImpl *)ownerDoc)->getPooledString(URI); -}; + setName(namespaceURI, qualifiedName); +} DOMElementNSImpl::DOMElementNSImpl(const DOMElementNSImpl &other, bool deep) : DOMElementImpl(other, deep) @@ -206,3 +179,44 @@ void DOMElementNSImpl::release() } } +DOMNode* DOMElementNSImpl::rename(const XMLCh* namespaceURI, const XMLCh* name) +{ + setName(namespaceURI, name); + fAttributes->reconcileDefaultAttributes(getDefaultAttributes()); + return this; +} + +void DOMElementNSImpl::setName(const XMLCh *namespaceURI, + const XMLCh *qualifiedName) +{ + DOMDocumentImpl* ownerDoc = (DOMDocumentImpl *) getOwnerDocument(); + this->fName = ownerDoc->getPooledString(qualifiedName); + + int index = DOMDocumentImpl::indexofQualifiedName(qualifiedName); + if (index < 0) + throw DOMException(DOMException::NAMESPACE_ERR, 0); + + if (index == 0) { //qualifiedName contains no ':' + this -> fPrefix = 0; + this -> fLocalName = this -> fName; + } else { //0 < index < this->name.length()-1 + XMLCh* newName; + XMLCh temp[4000]; + if (index >= 3999) + newName = new XMLCh[XMLString::stringLen(qualifiedName)+1]; + else + newName = temp; + + XMLString::copyNString(newName, fName, index); + newName[index] = chNull; + this-> fPrefix = ownerDoc->getPooledString(newName); + this -> fLocalName = ownerDoc->getPooledString(fName+index+1); + + if (index >= 3999) + delete[] newName; + } + + const XMLCh * URI = DOMNodeImpl::mapPrefix(fPrefix, namespaceURI, DOMNode::ELEMENT_NODE); + this -> fNamespaceURI = (URI == 0) ? 0 : ownerDoc->getPooledString(URI); +}; + diff --git a/src/xercesc/dom/impl/DOMElementNSImpl.hpp b/src/xercesc/dom/impl/DOMElementNSImpl.hpp index abd3aaf5030fe4eff474b918be4f9b86cb59cdb8..27b9f5630b84638b42e78af1a9220a9d3711ef07 100644 --- a/src/xercesc/dom/impl/DOMElementNSImpl.hpp +++ b/src/xercesc/dom/impl/DOMElementNSImpl.hpp @@ -95,6 +95,10 @@ public: virtual const XMLCh *getLocalName() const; virtual void setPrefix(const XMLCh *prefix); virtual void release(); + + // helper function for DOM Level 3 renameNode + virtual DOMNode* rename(const XMLCh* namespaceURI, const XMLCh* name); + void setName(const XMLCh* namespaceURI, const XMLCh* name); }; #endif