/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* * $Id$ */ #include "DOMElementImpl.hpp" #include #include #include #include #include #include "DOMAttrMapImpl.hpp" #include "DOMAttrImpl.hpp" #include "DOMDocumentImpl.hpp" #include "DOMParentNode.hpp" #include "DOMCasts.hpp" #include "DOMElementNSImpl.hpp" #include "DOMTypeInfoImpl.hpp" #include "DOMDocumentTypeImpl.hpp" #include XERCES_CPP_NAMESPACE_BEGIN class DOMAttr; DOMElementImpl::DOMElementImpl(DOMDocument *ownerDoc, const XMLCh *eName) : fNode(ownerDoc), fParent(ownerDoc), fAttributes(0), fDefaultAttributes(0) { DOMDocumentImpl *docImpl = (DOMDocumentImpl *)ownerDoc; fName = docImpl->getPooledString(eName); setupDefaultAttributes(); if (!fDefaultAttributes) { fDefaultAttributes = new (docImpl) DOMAttrMapImpl(this); fAttributes = new (docImpl) DOMAttrMapImpl(this); } else { fAttributes = new (docImpl) DOMAttrMapImpl(this, fDefaultAttributes); } } DOMElementImpl::DOMElementImpl(const DOMElementImpl &other, bool deep) : DOMElement(other), fNode (other.fParent.fOwnerDocument), fParent (other.fParent.fOwnerDocument), fAttributes(0), fDefaultAttributes(0) { fName = other.fName; if (deep) fParent.cloneChildren(&other); if (other.getAttributes()) { fAttributes = ((DOMAttrMapImpl *)other.getAttributes())->cloneAttrMap(this); } if (other.getDefaultAttributes()) { fDefaultAttributes = ((DOMAttrMapImpl *)other.getDefaultAttributes())->cloneAttrMap(this); } if (!fDefaultAttributes) setupDefaultAttributes(); if (!fDefaultAttributes) fDefaultAttributes = new (fParent.fOwnerDocument) DOMAttrMapImpl(this); if (!fAttributes) { if (!fDefaultAttributes) { fAttributes = new (fParent.fOwnerDocument) DOMAttrMapImpl(this); } else { fAttributes = new (fParent.fOwnerDocument) DOMAttrMapImpl(this, fDefaultAttributes); } } } DOMElementImpl::~DOMElementImpl() { } DOMNode *DOMElementImpl::cloneNode(bool deep) const { DOMNode* newNode = new (fParent.fOwnerDocument, DOMMemoryManager::ELEMENT_OBJECT) DOMElementImpl(*this, deep); fNode.callUserDataHandlers(DOMUserDataHandler::NODE_CLONED, this, newNode); return newNode; } const XMLCh * DOMElementImpl::getNodeName() const { return fName; } DOMNode::NodeType DOMElementImpl::getNodeType() const { return DOMNode::ELEMENT_NODE; } const XMLCh * DOMElementImpl::getAttribute(const XMLCh *nam) const { DOMNode * attr = fAttributes->getNamedItem(nam); if (attr) return attr->getNodeValue(); return XMLUni::fgZeroLenString; } DOMAttr *DOMElementImpl::getAttributeNode(const XMLCh *nam) const { return (DOMAttr *)fAttributes->getNamedItem(nam); } DOMNamedNodeMap *DOMElementImpl::getAttributes() const { DOMElementImpl *ncThis = (DOMElementImpl *)this; // cast off const return ncThis->fAttributes; } DOMNodeList *DOMElementImpl::getElementsByTagName(const XMLCh *tagname) const { DOMDocumentImpl *docImpl = (DOMDocumentImpl *)fParent.fOwnerDocument; return docImpl->getDeepNodeList(this,tagname); } const XMLCh * DOMElementImpl::getTagName() const { return fName; } void DOMElementImpl::removeAttribute(const XMLCh *nam) { if (fNode.isReadOnly()) throw DOMException( DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMNodeMemoryManager); int i = fAttributes->findNamePoint(nam); if (i >= 0) { DOMNode *att = fAttributes->removeNamedItemAt(i); ((DOMAttrImpl *)att)->removeAttrFromIDNodeMap(); att->release(); } } DOMAttr *DOMElementImpl::removeAttributeNode(DOMAttr *oldAttr) { if (fNode.isReadOnly()) throw DOMException( DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMNodeMemoryManager); DOMNode* found = 0; // Since there is no removeAttributeNodeNS, check if this oldAttr has NS or not const XMLCh* localName = oldAttr->getLocalName(); int 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); ((DOMAttrImpl *)oldAttr)->removeAttrFromIDNodeMap(); } else throw DOMException(DOMException::NOT_FOUND_ERR, 0, GetDOMNodeMemoryManager); } else throw DOMException(DOMException::NOT_FOUND_ERR, 0, GetDOMNodeMemoryManager); return (DOMAttr *)found; } void DOMElementImpl::setAttribute(const XMLCh *nam, const XMLCh *val) { if (fNode.isReadOnly()) throw DOMException( DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMNodeMemoryManager); DOMAttr* newAttr = getAttributeNode(nam); if (!newAttr) { newAttr = fParent.fOwnerDocument->createAttribute(nam); fAttributes->setNamedItem(newAttr); } newAttr->setNodeValue(val); } void DOMElementImpl::setIdAttribute(const XMLCh* name, bool isId) { if (fNode.isReadOnly()) throw DOMException( DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMNodeMemoryManager); DOMAttr *attr = getAttributeNode(name); if (!attr) throw DOMException(DOMException::NOT_FOUND_ERR, 0, GetDOMNodeMemoryManager); if(isId) ((DOMAttrImpl *)attr)->addAttrToIDNodeMap(); else ((DOMAttrImpl *)attr)->removeAttrFromIDNodeMap(); } void DOMElementImpl::setIdAttributeNS(const XMLCh* namespaceURI, const XMLCh* localName, bool isId) { if (fNode.isReadOnly()) throw DOMException( DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMNodeMemoryManager); DOMAttr *attr = getAttributeNodeNS(namespaceURI, localName); if (!attr) throw DOMException(DOMException::NOT_FOUND_ERR, 0, GetDOMNodeMemoryManager); if(isId) ((DOMAttrImpl *)attr)->addAttrToIDNodeMap(); else ((DOMAttrImpl *)attr)->removeAttrFromIDNodeMap(); } void DOMElementImpl::setIdAttributeNode(const DOMAttr *idAttr, bool isId) { if (fNode.isReadOnly()) throw DOMException( DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMNodeMemoryManager); DOMAttr *attr; const XMLCh* localName = idAttr->getLocalName(); if (localName) attr = getAttributeNodeNS(idAttr->getNamespaceURI(), idAttr->getLocalName()); else attr = getAttributeNode(idAttr->getName()); if(!attr) throw DOMException(DOMException::NOT_FOUND_ERR, 0, GetDOMNodeMemoryManager); if(isId) ((DOMAttrImpl *)attr)->addAttrToIDNodeMap(); else ((DOMAttrImpl *)attr)->removeAttrFromIDNodeMap(); } DOMAttr * DOMElementImpl::setAttributeNode(DOMAttr *newAttr) { if (fNode.isReadOnly()) throw DOMException( DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMNodeMemoryManager); if (newAttr->getNodeType() != DOMNode::ATTRIBUTE_NODE) throw DOMException(DOMException::WRONG_DOCUMENT_ERR, 0, GetDOMNodeMemoryManager); // revisit. Exception doesn't match test. // This will throw INUSE if necessary DOMAttr *oldAttr = (DOMAttr *) fAttributes->setNamedItem(newAttr); return oldAttr; } void DOMElementImpl::setNodeValue(const XMLCh *x) { fNode.setNodeValue(x); } void DOMElementImpl::setReadOnly(bool readOnl, bool deep) { fNode.setReadOnly(readOnl,deep); fAttributes->setReadOnly(readOnl,true); } //Introduced in DOM Level 2 const XMLCh * DOMElementImpl::getAttributeNS(const XMLCh *fNamespaceURI, const XMLCh *fLocalName) const { DOMAttr * attr= (DOMAttr *)(fAttributes->getNamedItemNS(fNamespaceURI, fLocalName)); return (attr==0) ? XMLUni::fgZeroLenString : attr->getValue(); } void DOMElementImpl::setAttributeNS(const XMLCh *fNamespaceURI, const XMLCh *qualifiedName, const XMLCh *fValue) { if (fNode.isReadOnly()) throw DOMException(DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMNodeMemoryManager); int index = DOMDocumentImpl::indexofQualifiedName(qualifiedName); if (index < 0) throw DOMException(DOMException::NAMESPACE_ERR, 0, GetDOMNodeMemoryManager); DOMAttr* newAttr = getAttributeNodeNS(fNamespaceURI, qualifiedName+index); if (!newAttr) { newAttr = fParent.fOwnerDocument->createAttributeNS(fNamespaceURI, qualifiedName); fAttributes->setNamedItemNS(newAttr); } newAttr->setNodeValue(fValue); } void DOMElementImpl::removeAttributeNS(const XMLCh *fNamespaceURI, const XMLCh *fLocalName) { if (fNode.isReadOnly()) throw DOMException( DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMNodeMemoryManager); int i = fAttributes->findNamePoint(fNamespaceURI, fLocalName); if (i >= 0) { DOMNode *att = fAttributes->removeNamedItemAt(i); att->release(); } } DOMAttr *DOMElementImpl::getAttributeNodeNS(const XMLCh *fNamespaceURI, const XMLCh *fLocalName) const { return (DOMAttr *)fAttributes->getNamedItemNS(fNamespaceURI, fLocalName); } DOMAttr *DOMElementImpl::setAttributeNodeNS(DOMAttr *newAttr) { if (fNode.isReadOnly()) throw DOMException( DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMNodeMemoryManager); if (newAttr -> getOwnerDocument() != fParent.fOwnerDocument) throw DOMException(DOMException::WRONG_DOCUMENT_ERR, 0, GetDOMNodeMemoryManager); // This will throw INUSE if necessary DOMAttr *oldAttr = (DOMAttr *) fAttributes->setNamedItemNS(newAttr); return oldAttr; } DOMNodeList *DOMElementImpl::getElementsByTagNameNS(const XMLCh *namespaceURI, const XMLCh *localName) const { DOMDocumentImpl *docImpl = (DOMDocumentImpl *)fParent.fOwnerDocument; return docImpl->getDeepNodeList(this, namespaceURI, localName); } bool DOMElementImpl::hasAttributes() const { return (fAttributes != 0 && fAttributes->getLength() != 0); } bool DOMElementImpl::hasAttribute(const XMLCh *name) const { return (getAttributeNode(name) != 0); } bool DOMElementImpl::hasAttributeNS(const XMLCh *namespaceURI, const XMLCh *localName) const { return (getAttributeNodeNS(namespaceURI, localName) != 0); } // util functions for default attributes // returns the default attribute map for this node from the owner document DOMAttrMapImpl *DOMElementImpl::getDefaultAttributes() const { return fDefaultAttributes; } // initially set up the default attribute information based on doctype information void DOMElementImpl::setupDefaultAttributes() { DOMDocument *tmpdoc = fParent.fOwnerDocument; if ((fNode.fOwnerNode == 0) || (tmpdoc == 0) || (tmpdoc->getDoctype() == 0)) return; DOMNode *eldef = ((DOMDocumentTypeImpl*)tmpdoc->getDoctype())->getElements()->getNamedItem(getNodeName()); DOMAttrMapImpl* defAttrs = (eldef == 0) ? 0 : (DOMAttrMapImpl *)(eldef->getAttributes()); if (defAttrs) fDefaultAttributes = new (tmpdoc) DOMAttrMapImpl(this, defAttrs); } DOMAttr * DOMElementImpl::setDefaultAttributeNode(DOMAttr *newAttr) { if (fNode.isReadOnly()) throw DOMException( DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMNodeMemoryManager); if (newAttr->getNodeType() != DOMNode::ATTRIBUTE_NODE) throw DOMException(DOMException::WRONG_DOCUMENT_ERR, 0, GetDOMNodeMemoryManager); // revisit. Exception doesn't match test. // This will throw INUSE if necessary DOMAttr *oldAttr = (DOMAttr *) fDefaultAttributes->setNamedItem(newAttr); fAttributes->hasDefaults(true); return oldAttr; } DOMAttr *DOMElementImpl::setDefaultAttributeNodeNS(DOMAttr *newAttr) { if (fNode.isReadOnly()) throw DOMException( DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMNodeMemoryManager); if (newAttr -> getOwnerDocument() != fParent.fOwnerDocument) throw DOMException(DOMException::WRONG_DOCUMENT_ERR, 0, GetDOMNodeMemoryManager); // This will throw INUSE if necessary DOMAttr *oldAttr = (DOMAttr *) fDefaultAttributes->setNamedItemNS(newAttr); fAttributes->hasDefaults(true); return oldAttr; } void DOMElementImpl::release() { if (fNode.isOwned() && !fNode.isToBeReleased()) throw DOMException(DOMException::INVALID_ACCESS_ERR,0, GetDOMNodeMemoryManager); DOMDocumentImpl* doc = (DOMDocumentImpl*) fParent.fOwnerDocument; if (doc) { fNode.callUserDataHandlers(DOMUserDataHandler::NODE_DELETED, 0, 0); // release children fParent.release(); // release attributes fAttributes->hasDefaults(false); XMLSize_t count; while((count = fAttributes->getLength()) != 0) { DOMNode* attr = fAttributes->removeNamedItemAt(count-1); attr->release(); } doc->release(this, DOMMemoryManager::ELEMENT_OBJECT); } else { // shouldn't reach here throw DOMException(DOMException::INVALID_ACCESS_ERR,0, GetDOMNodeMemoryManager); } } const XMLCh* DOMElementImpl::getBaseURI() const { const XMLCh* baseURI = fNode.fOwnerNode->getBaseURI(); if (fAttributes) { const XMLCh baseString[] = { chLatin_b, chLatin_a, chLatin_s, chLatin_e, chNull }; DOMNode* attrNode = fAttributes->getNamedItemNS(DOMNodeImpl::getXmlURIString(), baseString); if (attrNode==NULL) { const XMLCh xmlBaseString[] = { chLatin_x, chLatin_m, chLatin_l, chColon, chLatin_b, chLatin_a, chLatin_s, chLatin_e, chNull }; attrNode = fAttributes->getNamedItem(xmlBaseString); } if (attrNode) { const XMLCh* uri = attrNode->getNodeValue(); if (uri && *uri) {// attribute value is always empty string // if there is a base URI for the parent node, use it to resolve relative URI if(baseURI) { try { DOMDocumentImpl* doc = (DOMDocumentImpl *)fParent.fOwnerDocument; XMLUri temp(baseURI, doc->getMemoryManager()); XMLUri temp2(&temp, uri, doc->getMemoryManager()); uri = doc->cloneString(temp2.getUriText()); } catch(const OutOfMemoryException&) { throw; } catch (...){ // REVISIT: what should happen in this case? return 0; } } return uri; } } } return baseURI; } // // Functions inherited from Node // DOMNode* DOMElementImpl::appendChild(DOMNode *newChild) {return fParent.appendChild (newChild); } DOMNodeList* DOMElementImpl::getChildNodes() const {return fParent.getChildNodes (); } DOMNode* DOMElementImpl::getFirstChild() const {return fParent.getFirstChild (); } DOMNode* DOMElementImpl::getLastChild() const {return fParent.getLastChild (); } const XMLCh* DOMElementImpl::getLocalName() const {return fNode.getLocalName (); } const XMLCh* DOMElementImpl::getNamespaceURI() const {return fNode.getNamespaceURI (); } DOMNode* DOMElementImpl::getNextSibling() const {return fChild.getNextSibling (); } const XMLCh* DOMElementImpl::getNodeValue() const {return fNode.getNodeValue (); } DOMDocument* DOMElementImpl::getOwnerDocument() const {return fParent.fOwnerDocument; } const XMLCh* DOMElementImpl::getPrefix() const {return fNode.getPrefix (); } DOMNode* DOMElementImpl::getParentNode() const {return fChild.getParentNode (this); } DOMNode* DOMElementImpl::getPreviousSibling() const {return fChild.getPreviousSibling (this); } bool DOMElementImpl::hasChildNodes() const {return fParent.hasChildNodes (); } DOMNode* DOMElementImpl::insertBefore(DOMNode *newChild, DOMNode *refChild) {return fParent.insertBefore (newChild, refChild); } void DOMElementImpl::normalize() {fParent.normalize (); } DOMNode* DOMElementImpl::removeChild(DOMNode *oldChild) {return fParent.removeChild (oldChild); } DOMNode* DOMElementImpl::replaceChild(DOMNode *newChild, DOMNode *oldChild) {return fParent.replaceChild (newChild, oldChild); } bool DOMElementImpl::isSupported(const XMLCh *feature, const XMLCh *version) const {return fNode.isSupported (feature, version); } void DOMElementImpl::setPrefix(const XMLCh *prefix) {fNode.setPrefix(prefix); } bool DOMElementImpl::isSameNode(const DOMNode* other) const {return fNode.isSameNode(other); } void* DOMElementImpl::setUserData(const XMLCh* key, void* data, DOMUserDataHandler* handler) {return fNode.setUserData(key, data, handler); } void* DOMElementImpl::getUserData(const XMLCh* key) const {return fNode.getUserData(key); } short DOMElementImpl::compareDocumentPosition(const DOMNode* other) const {return fNode.compareDocumentPosition(other); } const XMLCh* DOMElementImpl::getTextContent() const {return fNode.getTextContent(); } void DOMElementImpl::setTextContent(const XMLCh* textContent){fNode.setTextContent(textContent); } const XMLCh* DOMElementImpl::lookupPrefix(const XMLCh* namespaceURI) const {return fNode.lookupPrefix(namespaceURI); } bool DOMElementImpl::isDefaultNamespace(const XMLCh* namespaceURI) const {return fNode.isDefaultNamespace(namespaceURI); } const XMLCh* DOMElementImpl::lookupNamespaceURI(const XMLCh* prefix) const {return fNode.lookupNamespaceURI(prefix); } void* DOMElementImpl::getFeature(const XMLCh* feature, const XMLCh* version) const {return fNode.getFeature(feature, version); } bool DOMElementImpl::isEqualNode(const DOMNode* arg) const { if (isSameNode(arg)) { return true; } if (!fNode.isEqualNode(arg)) { return false; } bool hasAttrs = hasAttributes(); if (hasAttrs != arg->hasAttributes()) { return false; } if (hasAttrs) { DOMNamedNodeMap* map1 = getAttributes(); DOMNamedNodeMap* map2 = arg->getAttributes(); XMLSize_t len = map1->getLength(); if (len != map2->getLength()) { return false; } for (XMLSize_t i = 0; i < len; i++) { DOMNode* n1 = map1->item(i); if (!n1->getLocalName()) { // DOM Level 1 Node DOMNode* n2 = map2->getNamedItem(n1->getNodeName()); if (!n2 || !n1->isEqualNode(n2)) { return false; } } else { DOMNode* n2 = map2->getNamedItemNS(n1->getNamespaceURI(), n1->getLocalName()); if (!n2 || !n1->isEqualNode(n2)) { return false; } } } } return fParent.isEqualNode(arg); } DOMNode* DOMElementImpl::rename(const XMLCh* namespaceURI, const XMLCh* name) { DOMDocumentImpl* doc = (DOMDocumentImpl*) fParent.fOwnerDocument; if (!namespaceURI || !*namespaceURI) { fName = doc->getPooledString(name); fAttributes->reconcileDefaultAttributes(getDefaultAttributes()); // and fire user data NODE_RENAMED event castToNodeImpl(this)->callUserDataHandlers(DOMUserDataHandler::NODE_RENAMED, this, this); 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; } } const DOMTypeInfo *DOMElementImpl::getSchemaTypeInfo() const { return &DOMTypeInfoImpl::g_DtdValidatedElement; } // DOMElementTraversal DOMElement * DOMElementImpl::getFirstElementChild() const { DOMNode* n = getFirstChild(); while (n != NULL) { switch (n->getNodeType()) { case DOMNode::ELEMENT_NODE: return (DOMElement*) n; case DOMNode::ENTITY_REFERENCE_NODE: { DOMElement* e = getFirstElementChild(n); if (e != NULL) return e; } break; default: break; } n = n->getNextSibling(); } return NULL; } DOMElement * DOMElementImpl::getLastElementChild() const { DOMNode* n = getLastChild(); while (n != NULL) { switch (n->getNodeType()) { case DOMNode::ELEMENT_NODE: return (DOMElement*) n; case DOMNode::ENTITY_REFERENCE_NODE: { DOMElement* e = getLastElementChild(n); if (e != NULL) return e; } break; default: break; } n = n->getPreviousSibling(); } return NULL; } DOMElement * DOMElementImpl::getNextElementSibling() const { DOMNode* n = getNextLogicalSibling(this); while (n != NULL) { switch (n->getNodeType()) { case DOMNode::ELEMENT_NODE: return (DOMElement*) n; case DOMNode::ENTITY_REFERENCE_NODE: { DOMElement* e = getFirstElementChild(n); if (e != NULL) return e; } break; default: break; } n = getNextLogicalSibling(n); } return NULL; } DOMElement * DOMElementImpl::getPreviousElementSibling() const { DOMNode* n = getPreviousLogicalSibling(this); while (n != NULL) { switch (n->getNodeType()) { case DOMNode::ELEMENT_NODE: return (DOMElement*) n; case DOMNode::ENTITY_REFERENCE_NODE: { DOMElement* e = getLastElementChild(n); if (e != NULL) return e; } break; default: break; } n = getPreviousLogicalSibling(n); } return NULL; } XMLSize_t DOMElementImpl::getChildElementCount() const { XMLSize_t count = 0; DOMElement* child = getFirstElementChild(); while (child != NULL) { ++count; child = child->getNextElementSibling(); } return count; } // Returns the first element node found from a // non-recursive in order traversal of the given node. DOMElement* DOMElementImpl::getFirstElementChild(const DOMNode* n) const { const DOMNode* top = n; while (n != NULL) { if (n->getNodeType() == DOMNode::ELEMENT_NODE) { return (DOMElement*) n; } DOMNode* next = n->getFirstChild(); while (next == NULL) { if (top == n) { break; } next = n->getNextSibling(); if (next == NULL) { n = n->getParentNode(); if (n == NULL || top == n) { return NULL; } } } n = next; } return NULL; } // Returns the first element node found from a // non-recursive reverse order traversal of the given node. DOMElement* DOMElementImpl::getLastElementChild(const DOMNode* n) const { const DOMNode* top = n; while (n != NULL) { if (n->getNodeType() == DOMNode::ELEMENT_NODE) { return (DOMElement*) n; } DOMNode* next = n->getLastChild(); while (next == NULL) { if (top == n) { break; } next = n->getPreviousSibling(); if (next == NULL) { n = n->getParentNode(); if (n == NULL || top == n) { return NULL; } } } n = next; } return NULL; } // Returns the next logical sibling with respect to the given node. DOMNode* DOMElementImpl::getNextLogicalSibling(const DOMNode* n) const { DOMNode* next = n->getNextSibling(); // If "n" has no following sibling and its parent is an entity reference node we // need to continue the search through the following siblings of the entity // reference as these are logically siblings of the given node. if (next == NULL) { DOMNode* parent = n->getParentNode(); while (parent != NULL && parent->getNodeType() == DOMNode::ENTITY_REFERENCE_NODE) { next = parent->getNextSibling(); if (next != NULL) { break; } parent = parent->getParentNode(); } } return next; } // Returns the previous logical sibling with respect to the given node. DOMNode* DOMElementImpl::getPreviousLogicalSibling(const DOMNode* n) const { DOMNode* prev = n->getPreviousSibling(); // If "n" has no previous sibling and its parent is an entity reference node we // need to continue the search through the previous siblings of the entity // reference as these are logically siblings of the given node. if (prev == NULL) { DOMNode* parent = n->getParentNode(); while (parent != NULL && parent->getNodeType() == DOMNode::ENTITY_REFERENCE_NODE) { prev = parent->getPreviousSibling(); if (prev != NULL) { break; } parent = parent->getParentNode(); } } return prev; } XERCES_CPP_NAMESPACE_END