/* * Copyright 2001-2004 The Apache Software Foundation. * * Licensed 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: DOMNodeImpl.cpp 180016 2005-06-04 19:49:30Z jberry $ */ // This class doesn't support having any children, and implements the behavior // of an empty NodeList as far getChildNodes is concerned. // The ParentNode subclass overrides this behavior. #include "DOMCasts.hpp" #include "DOMDocumentTypeImpl.hpp" #include "DOMElementImpl.hpp" #include "DOMAttrImpl.hpp" #include #include #include #include #include #include #include #include XERCES_CPP_NAMESPACE_BEGIN //Though DOMNodeImpl does not derivate from DOMNode, it shares //the same GetDOMNodeMemoryManager const unsigned short DOMNodeImpl::READONLY = 0x1<<0; const unsigned short DOMNodeImpl::SYNCDATA = 0x1<<1; const unsigned short DOMNodeImpl::SYNCCHILDREN = 0x1<<2; const unsigned short DOMNodeImpl::OWNED = 0x1<<3; const unsigned short DOMNodeImpl::FIRSTCHILD = 0x1<<4; const unsigned short DOMNodeImpl::SPECIFIED = 0x1<<5; const unsigned short DOMNodeImpl::IGNORABLEWS = 0x1<<6; const unsigned short DOMNodeImpl::SETVALUE = 0x1<<7; const unsigned short DOMNodeImpl::ID_ATTR = 0x1<<8; const unsigned short DOMNodeImpl::USERDATA = 0x1<<9; const unsigned short DOMNodeImpl::LEAFNODETYPE = 0x1<<10; const unsigned short DOMNodeImpl::CHILDNODE = 0x1<<11; const unsigned short DOMNodeImpl::TOBERELEASED = 0x1<<12; // ----------------------------------------------------------------------- // Reset the singleton gEmptyNodeList // ----------------------------------------------------------------------- static DOMNodeListImpl *gEmptyNodeList = 0; // make a singleton empty node list static XMLMutex* gEmptyNodeListMutex = 0; static XMLRegisterCleanup emptyNodeListCleanup; static void reinitEmptyNodeList() { delete gEmptyNodeList; gEmptyNodeList = 0; delete gEmptyNodeListMutex; gEmptyNodeListMutex = 0; } void XMLInitializer::initializeEmptyNodeList() { gEmptyNodeList = new DOMNodeListImpl(0); if (gEmptyNodeList) { emptyNodeListCleanup.registerCleanup(reinitEmptyNodeList); } } // ----------------------------------------------------------------------- // DOMNodeImpl Functions // ----------------------------------------------------------------------- DOMNodeImpl::DOMNodeImpl(DOMNode *ownerNode) : fOwnerNode(ownerNode) { this->flags = 0; // as long as we do not have any owner, fOwnerNode is our ownerDocument } // This only makes a shallow copy, cloneChildren must also be called for a // deep clone DOMNodeImpl::DOMNodeImpl(const DOMNodeImpl &other) { this->flags = other.flags; this->isReadOnly(false); // Need to break the association w/ original parent this->fOwnerNode = other.getOwnerDocument(); this->isOwned(false); } DOMNodeImpl::~DOMNodeImpl() { } DOMNode * DOMNodeImpl::appendChild(DOMNode *) { // Only node types that don't allow children will use this default function. // Others will go to DOMParentNode::appendChild. throw DOMException(DOMException::HIERARCHY_REQUEST_ERR,0, GetDOMNodeMemoryManager); return 0; // return insertBefore(newChild, 0); } DOMNamedNodeMap * DOMNodeImpl::getAttributes() const { return 0; // overridden in ElementImpl } DOMNodeList *DOMNodeImpl::getChildNodes() const { if (!gEmptyNodeList) { if (!gEmptyNodeListMutex) { XMLMutexLock lock(XMLPlatformUtils::fgAtomicMutex); if (!gEmptyNodeListMutex) gEmptyNodeListMutex = new XMLMutex(XMLPlatformUtils::fgMemoryManager); } // Use a faux scope to synchronize while we do this { XMLMutexLock lock(gEmptyNodeListMutex); if (!gEmptyNodeList) { gEmptyNodeList = new DOMNodeListImpl(0); emptyNodeListCleanup.registerCleanup(reinitEmptyNodeList); } } } return (DOMNodeList *)gEmptyNodeList; } DOMNode * DOMNodeImpl::getFirstChild() const { return 0; // overridden in ParentNode } DOMNode * DOMNodeImpl::getLastChild() const { return 0; // overridden in ParentNode } DOMNode * DOMNodeImpl::getNextSibling() const { return 0; // overridden in ChildNode } const XMLCh * DOMNodeImpl::getNodeValue() const { return 0; // Overridden by anything that has a value } // // Unlike the external getOwnerDocument, this one returns the owner document // for document nodes as well as all of the other node types. // DOMDocument *DOMNodeImpl::getOwnerDocument() const { if (!this->isLeafNode()) { DOMElementImpl *ep = (DOMElementImpl *)castToNode(this); return ep->fParent.fOwnerDocument; } // Leaf node types - those that cannot have children, like Text. if (isOwned()) { DOMDocument* ownerDoc = fOwnerNode->getOwnerDocument(); if (!ownerDoc) { assert (fOwnerNode->getNodeType() == DOMNode::DOCUMENT_NODE); return (DOMDocument *)fOwnerNode; } else { return ownerDoc; } } else { assert (fOwnerNode->getNodeType() == DOMNode::DOCUMENT_NODE); return (DOMDocument *)fOwnerNode; } } void DOMNodeImpl::setOwnerDocument(DOMDocument *doc) { // if we have an owner we rely on it to have it right // otherwise fOwnerNode is our ownerDocument if (!isOwned()) { // revisit. Problem with storage for doctype nodes that were created // on the system heap in advance of having a document. fOwnerNode = doc; } } DOMNode * DOMNodeImpl::getParentNode() const { return 0; // overridden in ChildNode } DOMNode* DOMNodeImpl::getPreviousSibling() const { return 0; // overridden in ChildNode } bool DOMNodeImpl::hasChildNodes() const { return false; } DOMNode *DOMNodeImpl::insertBefore(DOMNode *, DOMNode *) { throw DOMException(DOMException::HIERARCHY_REQUEST_ERR, 0, GetDOMNodeMemoryManager); return 0; } DOMNode *DOMNodeImpl::removeChild(DOMNode *) { throw DOMException(DOMException::NOT_FOUND_ERR, 0, GetDOMNodeMemoryManager); return 0; } DOMNode *DOMNodeImpl::replaceChild(DOMNode *, DOMNode *) { throw DOMException(DOMException::HIERARCHY_REQUEST_ERR,0, GetDOMNodeMemoryManager); return 0; } void DOMNodeImpl::setNodeValue(const XMLCh *) { // Default behavior is to do nothing, overridden in some subclasses } void DOMNodeImpl::setReadOnly(bool readOnl, bool deep) { this->isReadOnly(readOnl); if (deep) { for (DOMNode *mykid = castToNode(this)->getFirstChild(); mykid != 0; mykid = mykid->getNextSibling()) { short kidNodeType = mykid->getNodeType(); switch (kidNodeType) { case DOMNode::ENTITY_REFERENCE_NODE: break; case DOMNode::ELEMENT_NODE: ((DOMElementImpl*) mykid)->setReadOnly(readOnl, true); break; case DOMNode::DOCUMENT_TYPE_NODE: ((DOMDocumentTypeImpl*) mykid)->setReadOnly(readOnl, true); break; default: castToNodeImpl(mykid)->setReadOnly(readOnl, true); break; } } } } //Introduced in DOM Level 2 void DOMNodeImpl::normalize() { // does nothing by default, overridden by subclasses } bool DOMNodeImpl::isSupported(const XMLCh *feature, const XMLCh *version) const { return DOMImplementation::getImplementation()->hasFeature(feature, version); } const XMLCh *DOMNodeImpl::getNamespaceURI() const { return 0; } const XMLCh *DOMNodeImpl::getPrefix() const { return 0; } const XMLCh *DOMNodeImpl::getLocalName() const { return 0; } void DOMNodeImpl::setPrefix(const XMLCh *) { throw DOMException(DOMException::NAMESPACE_ERR, 0, GetDOMNodeMemoryManager); } bool DOMNodeImpl::hasAttributes() const { return 0; // overridden in ElementImpl } const XMLCh *DOMNodeImpl::getXmlString() {return XMLUni::fgXMLString;} const XMLCh *DOMNodeImpl::getXmlURIString() {return XMLUni::fgXMLURIName;} const XMLCh *DOMNodeImpl::getXmlnsString() {return XMLUni::fgXMLNSString;} const XMLCh *DOMNodeImpl::getXmlnsURIString() {return XMLUni::fgXMLNSURIName;} //Return a URI mapped from the given prefix and namespaceURI as below // prefix namespaceURI output //--------------------------------------------------- // "xml" xmlURI xmlURI // "xml" otherwise NAMESPACE_ERR // "xmlns" xmlnsURI xmlnsURI (nType = ATTRIBUTE_NODE only) // "xmlns" otherwise NAMESPACE_ERR (nType = ATTRIBUTE_NODE only) // != null null or "" NAMESPACE_ERR // else any namesapceURI const XMLCh* DOMNodeImpl::mapPrefix(const XMLCh *prefix, const XMLCh *namespaceURI, short nType) { if (prefix == 0) return namespaceURI; if (XMLString::equals(prefix, XMLUni::fgXMLString)) { if (XMLString::equals(namespaceURI, XMLUni::fgXMLURIName)) return XMLUni::fgXMLURIName; throw DOMException(DOMException::NAMESPACE_ERR, 0); } else if (nType == DOMNode::ATTRIBUTE_NODE && XMLString::equals(prefix, XMLUni::fgXMLNSString)) { if (XMLString::equals(namespaceURI, XMLUni::fgXMLNSURIName)) return XMLUni::fgXMLNSURIName; throw DOMException(DOMException::NAMESPACE_ERR, 0); } else if (namespaceURI == 0 || *namespaceURI == 0) throw DOMException(DOMException::NAMESPACE_ERR, 0); return namespaceURI; } //Introduced in DOM Level 3 void* DOMNodeImpl::setUserData(const XMLCh* key, void* data, DOMUserDataHandler* handler) { if (!data && !hasUserData()) return 0; hasUserData(true); return ((DOMDocumentImpl*)getOwnerDocument())->setUserData(this, key, data, handler); } void* DOMNodeImpl::getUserData(const XMLCh* key) const { if (hasUserData()) return ((DOMDocumentImpl*)getOwnerDocument())->getUserData(this, key); return 0; } void DOMNodeImpl::callUserDataHandlers(DOMUserDataHandler::DOMOperationType operation, const DOMNode* src, const DOMNode* dst) const { DOMDocumentImpl* doc=(DOMDocumentImpl*)getOwnerDocument(); if (doc) doc->callUserDataHandlers(this, operation, src, dst); } bool DOMNodeImpl::isSameNode(const DOMNode* other) const { return (castToNode(this) == other); } bool DOMNodeImpl::isEqualNode(const DOMNode* arg) const { if (!arg) return false; if (isSameNode(arg)) { return true; } DOMNode* thisNode = castToNode(this); if (arg->getNodeType() != thisNode->getNodeType()) { return false; } // the compareString will check null string as well if (!XMLString::equals(thisNode->getNodeName(), arg->getNodeName())) { return false; } if (!XMLString::equals(thisNode->getLocalName(),arg->getLocalName())) { return false; } if (!XMLString::equals(thisNode->getNamespaceURI(), arg->getNamespaceURI())) { return false; } if (!XMLString::equals(thisNode->getPrefix(), arg->getPrefix())) { return false; } if (!XMLString::equals(thisNode->getNodeValue(), arg->getNodeValue())) { return false; } if (!XMLString::equals(thisNode->getBaseURI(), arg->getBaseURI())) { return false; } return true; } const XMLCh* DOMNodeImpl::lookupNamespacePrefix(const XMLCh* namespaceURI, bool useDefault) const { // REVISIT: When Namespaces 1.1 comes out this may not be true // Prefix can't be bound to null namespace if (namespaceURI == 0) { return 0; } DOMNode *thisNode = castToNode(this); short type = thisNode->getNodeType(); switch (type) { case DOMNode::ELEMENT_NODE: { return lookupNamespacePrefix(namespaceURI, useDefault, (DOMElement*)thisNode); } case DOMNode::DOCUMENT_NODE:{ return ((DOMDocument*)thisNode)->getDocumentElement()->lookupNamespacePrefix(namespaceURI, useDefault); } case DOMNode::ENTITY_NODE : case DOMNode::NOTATION_NODE: case DOMNode::DOCUMENT_FRAGMENT_NODE: case DOMNode::DOCUMENT_TYPE_NODE: // type is unknown return 0; case DOMNode::ATTRIBUTE_NODE:{ if (fOwnerNode->getNodeType() == DOMNode::ELEMENT_NODE) { return fOwnerNode->lookupNamespacePrefix(namespaceURI, useDefault); } return 0; } default:{ DOMNode *ancestor = getElementAncestor(thisNode); if (ancestor != 0) { return ancestor->lookupNamespacePrefix(namespaceURI, useDefault); } return 0; } } } DOMNode* DOMNodeImpl::getElementAncestor (const DOMNode* currentNode) const { DOMNode* parent = currentNode->getParentNode(); if (parent != 0) { short type = parent->getNodeType(); if (type == DOMNode::ELEMENT_NODE) { return parent; } return getElementAncestor(parent); } return 0; } const XMLCh* DOMNodeImpl::lookupNamespacePrefix(const XMLCh* const namespaceURI, bool useDefault, DOMElement *el) const { DOMNode *thisNode = castToNode(this); const XMLCh* ns = thisNode->getNamespaceURI(); // REVISIT: if no prefix is available is it null or empty string, or // could be both? const XMLCh* prefix = thisNode->getPrefix(); if (ns != 0 && XMLString::equals(ns,namespaceURI)) { if (useDefault || prefix != 0) { const XMLCh* foundNamespace = el->lookupNamespaceURI(prefix); if (foundNamespace != 0 && XMLString::equals(foundNamespace, namespaceURI)) { return prefix; } } } if (thisNode->hasAttributes()) { DOMNamedNodeMap *nodeMap = thisNode->getAttributes(); if(nodeMap != 0) { int length = nodeMap->getLength(); for (int i = 0;i < length;i++) { DOMNode *attr = nodeMap->item(i); const XMLCh* attrPrefix = attr->getPrefix(); const XMLCh* value = attr->getNodeValue(); ns = attr->getNamespaceURI(); if (ns != 0 && XMLString::equals(ns, XMLUni::fgXMLNSURIName)) { // DOM Level 2 nodes if ((useDefault && XMLString::equals(attr->getNodeName(), XMLUni::fgXMLNSString)) || (attrPrefix != 0 && XMLString::equals(attrPrefix, XMLUni::fgXMLNSString)) && XMLString::equals(value, namespaceURI)) { const XMLCh* localname= attr->getLocalName(); const XMLCh* foundNamespace = el->lookupNamespaceURI(localname); if (foundNamespace != 0 && XMLString::equals(foundNamespace, namespaceURI)) { return localname; } } } } } } DOMNode *ancestor = getElementAncestor(thisNode); if (ancestor != 0) { return castToNodeImpl(ancestor)->lookupNamespacePrefix(namespaceURI, useDefault, el); } return 0; } const XMLCh* DOMNodeImpl::lookupNamespaceURI(const XMLCh* specifiedPrefix) const { DOMNode *thisNode = castToNode(this); short type = thisNode->getNodeType(); switch (type) { case DOMNode::ELEMENT_NODE : { const XMLCh* ns = thisNode->getNamespaceURI(); const XMLCh* prefix = thisNode->getPrefix(); if (ns != 0) { // REVISIT: is it possible that prefix is empty string? if (specifiedPrefix == 0 && prefix == specifiedPrefix) { // looking for default namespace return ns; } else if (prefix != 0 && XMLString::equals(prefix, specifiedPrefix)) { // non default namespace return ns; } } if (thisNode->hasAttributes()) { DOMNamedNodeMap *nodeMap = thisNode->getAttributes(); if(nodeMap != 0) { int length = nodeMap->getLength(); for (int i = 0;i < length;i++) { DOMNode *attr = nodeMap->item(i); const XMLCh *attrPrefix = attr->getPrefix(); const XMLCh *value = attr->getNodeValue(); ns = attr->getNamespaceURI(); if (ns != 0 && XMLString::equals(ns, XMLUni::fgXMLNSURIName)) { // at this point we are dealing with DOM Level 2 nodes only if (specifiedPrefix == 0 && XMLString::equals(attr->getNodeName(), XMLUni::fgXMLNSString)) { // default namespace return value; } else if (attrPrefix != 0 && XMLString::equals(attrPrefix, XMLUni::fgXMLNSString) && XMLString::equals(attr->getLocalName(), specifiedPrefix)) { // non default namespace return value; } } } } } DOMNode *ancestor = getElementAncestor(thisNode); if (ancestor != 0) { return ancestor->lookupNamespaceURI(specifiedPrefix); } return 0; } case DOMNode::DOCUMENT_NODE : { return((DOMDocument*)thisNode)->getDocumentElement()->lookupNamespaceURI(specifiedPrefix); } case DOMNode::ENTITY_NODE : case DOMNode::NOTATION_NODE: case DOMNode::DOCUMENT_FRAGMENT_NODE: case DOMNode::DOCUMENT_TYPE_NODE: // type is unknown return 0; case DOMNode::ATTRIBUTE_NODE:{ if (fOwnerNode->getNodeType() == DOMNode::ELEMENT_NODE) { return fOwnerNode->lookupNamespaceURI(specifiedPrefix); } return 0; } default:{ DOMNode *ancestor = getElementAncestor(castToNode(this)); if (ancestor != 0) { return ancestor->lookupNamespaceURI(specifiedPrefix); } return 0; } } } const XMLCh* DOMNodeImpl::getBaseURI() const{ DOMNode *thisNode = castToNode(this); DOMNode* parent = thisNode->getParentNode(); if (parent) return parent->getBaseURI(); else return 0; } short DOMNodeImpl::compareTreePosition(const DOMNode* other) const { // Questions of clarification for this method - to be answered by the // DOM WG. Current assumptions listed - LM // // 1. How do ENTITY nodes compare? // Current assumption: TREE_POSITION_DISCONNECTED, as ENTITY nodes // aren't really 'in the tree' // // 2. How do NOTATION nodes compare? // Current assumption: TREE_POSITION_DISCONNECTED, as NOTATION nodes // aren't really 'in the tree' // // 3. Are TREE_POSITION_ANCESTOR and TREE_POSITION_DESCENDANT // only relevant for nodes that are "part of the document tree"? // // // // Is the element node "outer" considered an ancestor of "myattr"? // Current assumption: No. // // 4. How do children of ATTRIBUTE nodes compare (with eachother, or // with children of other attribute nodes with the same element) // Current assumption: Children of ATTRIBUTE nodes are treated as if // they are the attribute node itself, unless the 2 nodes // are both children of the same attribute. // // 5. How does an ENTITY_REFERENCE node compare with it's children? // Given the DOM, it should precede its children as an ancestor. // Given "document order", does it represent the same position? // Current assumption: An ENTITY_REFERENCE node is an ancestor of its // children. // // 6. How do children of a DocumentFragment compare? // Current assumption: If both nodes are part of the same document // fragment, there are compared as if they were part of a document. DOMNode* thisNode = castToNode(this); // If the nodes are the same... if (thisNode == other) return (DOMNode::TREE_POSITION_SAME_NODE | DOMNode::TREE_POSITION_EQUIVALENT); // If either node is of type ENTITY or NOTATION, compare as disconnected short thisType = thisNode->getNodeType(); short otherType = other->getNodeType(); // If either node is of type ENTITY or NOTATION, compare as disconnected if (thisType == DOMNode::ENTITY_NODE || thisType == DOMNode::NOTATION_NODE || otherType == DOMNode::ENTITY_NODE || otherType == DOMNode::NOTATION_NODE ) { return DOMNode::TREE_POSITION_DISCONNECTED; } //if this is a custom node, we don't really know what to do, just return //user should provide its own compareTreePosition logic, and shouldn't reach here if(thisType > 12) { return 0; } //if it is a custom node we must ask it for the order if(otherType > 12) { return reverseTreeOrderBitPattern(other->compareTreePosition(castToNode(this))); } // Find the ancestor of each node, and the distance each node is from // its ancestor. // During this traversal, look for ancestor/descendent relationships // between the 2 nodes in question. // We do this now, so that we get this info correct for attribute nodes // and their children. const DOMNode *node; const DOMNode *thisAncestor = castToNode(this); const DOMNode *otherAncestor = other; int thisDepth=0; int otherDepth=0; for (node = castToNode(this); node != 0; node = node->getParentNode()) { thisDepth +=1; if (node == other) // The other node is an ancestor of this one. return (DOMNode::TREE_POSITION_ANCESTOR | DOMNode::TREE_POSITION_PRECEDING); thisAncestor = node; } for (node=other; node != 0; node = node->getParentNode()) { otherDepth +=1; if (node == castToNode(this)) // The other node is a descendent of the reference node. return (DOMNode::TREE_POSITION_DESCENDANT | DOMNode::TREE_POSITION_FOLLOWING); otherAncestor = node; } const DOMNode *otherNode = other; short thisAncestorType = thisAncestor->getNodeType(); short otherAncestorType = otherAncestor->getNodeType(); // if the ancestor is an attribute, get owning element. // we are now interested in the owner to determine position. if (thisAncestorType == DOMNode::ATTRIBUTE_NODE) { thisNode = ((DOMAttrImpl *)thisAncestor)->getOwnerElement(); } if (otherAncestorType == DOMNode::ATTRIBUTE_NODE) { otherNode = ((DOMAttrImpl *)otherAncestor)->getOwnerElement(); } // Before proceeding, we should check if both ancestor nodes turned // out to be attributes for the same element if (thisAncestorType == DOMNode::ATTRIBUTE_NODE && otherAncestorType == DOMNode::ATTRIBUTE_NODE && thisNode==otherNode) return DOMNode::TREE_POSITION_EQUIVALENT; // Now, find the ancestor of the owning element, if the original // ancestor was an attribute if (thisAncestorType == DOMNode::ATTRIBUTE_NODE) { thisDepth=0; for (node=thisNode; node != 0; node = node->getParentNode()) { thisDepth +=1; if (node == otherNode) // The other node is an ancestor of the owning element return DOMNode::TREE_POSITION_PRECEDING; thisAncestor = node; } for (node=otherNode; node != 0; node = node->getParentNode()) { if (node == thisNode) // The other node is an ancestor of the owning element return DOMNode::TREE_POSITION_FOLLOWING; } } // Now, find the ancestor of the owning element, if the original // ancestor was an attribute if (otherAncestorType == DOMNode::ATTRIBUTE_NODE) { otherDepth=0; for (node=otherNode; node != 0; node = node->getParentNode()) { otherDepth +=1; if (node == thisNode) // The other node is a descendent of the reference // node's element return DOMNode::TREE_POSITION_FOLLOWING; otherAncestor = node; } for (node=thisNode; node != 0; node = node->getParentNode()) { if (node == otherNode) // The other node is an ancestor of the owning element return DOMNode::TREE_POSITION_PRECEDING; } } // thisAncestor and otherAncestor must be the same at this point, // otherwise, we are not in the same tree or document fragment if (thisAncestor != otherAncestor) return DOMNode::TREE_POSITION_DISCONNECTED; // Determine which node is of the greatest depth. if (thisDepth > otherDepth) { for (int i= 0 ; i < thisDepth - otherDepth; i++) thisNode = thisNode->getParentNode(); } else { for (int i = 0; i < otherDepth - thisDepth; i++) otherNode = otherNode->getParentNode(); } // We now have nodes at the same depth in the tree. Find a common // ancestor. DOMNode *thisNodeP, *otherNodeP; for (thisNodeP = thisNode->getParentNode(), otherNodeP = otherNode->getParentNode(); thisNodeP != otherNodeP;) { thisNode = thisNodeP; otherNode = otherNodeP; thisNodeP = thisNodeP->getParentNode(); otherNodeP = otherNodeP->getParentNode(); } // See whether thisNode or otherNode is the leftmost for (DOMNode *current = thisNodeP->getFirstChild(); current != 0; current = current->getNextSibling()) { if (current == otherNode) { return DOMNode::TREE_POSITION_PRECEDING; } else if (current == thisNode) { return DOMNode::TREE_POSITION_FOLLOWING; } } // REVISIT: shouldn't get here. Should probably throw an // exception return 0; } short DOMNodeImpl::reverseTreeOrderBitPattern(short pattern) const { if(pattern & DOMNode::TREE_POSITION_PRECEDING) { pattern &= !DOMNode::TREE_POSITION_PRECEDING; pattern |= DOMNode::TREE_POSITION_FOLLOWING; } else if(pattern & DOMNode::TREE_POSITION_FOLLOWING) { pattern &= !DOMNode::TREE_POSITION_FOLLOWING; pattern |= DOMNode::TREE_POSITION_PRECEDING; } if(pattern & DOMNode::TREE_POSITION_ANCESTOR) { pattern &= !DOMNode::TREE_POSITION_ANCESTOR; pattern |= DOMNode::TREE_POSITION_DESCENDANT; } else if(pattern & DOMNode::TREE_POSITION_DESCENDANT) { pattern &= !DOMNode::TREE_POSITION_DESCENDANT; pattern |= DOMNode::TREE_POSITION_ANCESTOR; } return pattern; } /*** * * Excerpt from http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/core.html#Node3-textContent * * textContent of type DOMString, introduced in DOM Level 3 * * This attribute returns the text content of this node and its descendants. When it is defined * to be null, setting it has no effect. * * When set, any possible children this node may have are removed and replaced by a single Text node * containing the string this attribute is set to. * * On getting, no serialization is performed, the returned string does not contain any markup. * No whitespace normalization is performed, the returned string does not contain the element content * whitespaces Fundamental Interfaces. * * Similarly, on setting, no parsing is performed either, the input string is taken as pure textual content. * * The string returned is made of the text content of this node depending on its type, * as defined below: * * Node type Content * ==================== ======================================================================== * ELEMENT_NODE concatenation of the textContent attribute value of every child node, * ENTITY_NODE excluding COMMENT_NODE and PROCESSING_INSTRUCTION_NODE nodes. * ENTITY_REFERENCE_NODE This is the empty string if the node has no children. * DOCUMENT_FRAGMENT_NODE * -------------------------------------------------------------------------------------------------- * ATTRIBUTE_NODE * TEXT_NODE * CDATA_SECTION_NODE * COMMENT_NODE, * PROCESSING_INSTRUCTION_NODE nodeValue * -------------------------------------------------------------------------------------------------- * DOCUMENT_NODE, * DOCUMENT_TYPE_NODE, * NOTATION_NODE null * ***/ const XMLCh* DOMNodeImpl::getTextContent() const { unsigned int nBufferLength = 0; getTextContent(NULL, nBufferLength); XMLCh* pzBuffer = (XMLCh*)((DOMDocumentImpl*)getOwnerDocument())->allocate((nBufferLength+1) * sizeof(XMLCh)); getTextContent(pzBuffer, nBufferLength); pzBuffer[nBufferLength] = 0; return pzBuffer; } const XMLCh* DOMNodeImpl::getTextContent(XMLCh* pzBuffer, unsigned int& rnBufferLength) const { unsigned int nRemainingBuffer = rnBufferLength; rnBufferLength = 0; if (pzBuffer) *pzBuffer = 0; DOMNode *thisNode = castToNode(this); switch (thisNode->getNodeType()) { case DOMNode::ELEMENT_NODE: case DOMNode::ENTITY_NODE: case DOMNode::ENTITY_REFERENCE_NODE: case DOMNode::DOCUMENT_FRAGMENT_NODE: { DOMNode* current = thisNode->getFirstChild(); while (current != NULL) { if (current->getNodeType() != DOMNode::COMMENT_NODE && current->getNodeType() != DOMNode::PROCESSING_INSTRUCTION_NODE) { if (pzBuffer) { unsigned int nContentLength = nRemainingBuffer; castToNodeImpl(current)->getTextContent(pzBuffer + rnBufferLength, nContentLength); rnBufferLength += nContentLength; nRemainingBuffer -= nContentLength; } else { unsigned int nContentLength = 0; castToNodeImpl(current)->getTextContent(NULL, nContentLength); rnBufferLength += nContentLength; } } current = current->getNextSibling(); } } break; case DOMNode::ATTRIBUTE_NODE: case DOMNode::TEXT_NODE: case DOMNode::CDATA_SECTION_NODE: case DOMNode::COMMENT_NODE: case DOMNode::PROCESSING_INSTRUCTION_NODE: { const XMLCh* pzValue = thisNode->getNodeValue(); unsigned int nStrLen = XMLString::stringLen(pzValue); if (pzBuffer) { unsigned int nContentLength = (nRemainingBuffer >= nStrLen) ? nStrLen : nRemainingBuffer; XMLString::copyNString(pzBuffer + rnBufferLength, pzValue, nContentLength); rnBufferLength += nContentLength; nRemainingBuffer -= nContentLength; } else { rnBufferLength += nStrLen; } } break; /*** DOCUMENT_NODE DOCUMENT_TYPE_NODE NOTATION_NODE ***/ default: break; } return pzBuffer; } void DOMNodeImpl::setTextContent(const XMLCh* textContent){ DOMNode *thisNode = castToNode(this); switch (thisNode->getNodeType()) { case DOMNode::ELEMENT_NODE: case DOMNode::ENTITY_NODE: case DOMNode::ENTITY_REFERENCE_NODE: case DOMNode::DOCUMENT_FRAGMENT_NODE: { if (isReadOnly()) throw DOMException(DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMNodeMemoryManager); // Remove all childs DOMNode* current = thisNode->getFirstChild(); while (current != NULL) { thisNode->removeChild(current); current = thisNode->getFirstChild(); } if (textContent != NULL) { // Add textnode containing data current = ((DOMDocumentImpl*)thisNode->getOwnerDocument())->createTextNode(textContent); thisNode->appendChild(current); } } break; case DOMNode::ATTRIBUTE_NODE: case DOMNode::TEXT_NODE: case DOMNode::CDATA_SECTION_NODE: case DOMNode::COMMENT_NODE: case DOMNode::PROCESSING_INSTRUCTION_NODE: if (isReadOnly()) throw DOMException(DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMNodeMemoryManager); thisNode->setNodeValue(textContent); break; case DOMNode::DOCUMENT_NODE: case DOMNode::DOCUMENT_TYPE_NODE: case DOMNode::NOTATION_NODE: break; default: throw DOMException(DOMException::NOT_SUPPORTED_ERR, 0, GetDOMNodeMemoryManager); } } bool DOMNodeImpl::isDefaultNamespace(const XMLCh* namespaceURI) const{ DOMNode *thisNode = castToNode(this); short type = thisNode->getNodeType(); switch (type) { case DOMNode::ELEMENT_NODE: { const XMLCh *prefix = thisNode->getPrefix(); // REVISIT: is it possible that prefix is empty string? if (prefix == 0 || !*prefix) { return XMLString::equals(namespaceURI, thisNode->getNamespaceURI()); } if (thisNode->hasAttributes()) { DOMElement *elem = (DOMElement *)thisNode; DOMNode *attr = elem->getAttributeNodeNS(XMLUni::fgXMLNSURIName, XMLUni::fgXMLNSString); if (attr != 0) { const XMLCh *value = attr->getNodeValue(); return XMLString::equals(namespaceURI, value); } } DOMNode *ancestor = getElementAncestor(thisNode); if (ancestor != 0) { return ancestor->isDefaultNamespace(namespaceURI); } return false; } case DOMNode::DOCUMENT_NODE:{ return ((DOMDocument*)thisNode)->getDocumentElement()->isDefaultNamespace(namespaceURI); } case DOMNode::ENTITY_NODE : case DOMNode::NOTATION_NODE: case DOMNode::DOCUMENT_FRAGMENT_NODE: case DOMNode::DOCUMENT_TYPE_NODE: // type is unknown return false; case DOMNode::ATTRIBUTE_NODE:{ if (fOwnerNode->getNodeType() == DOMNode::ELEMENT_NODE) { return fOwnerNode->isDefaultNamespace(namespaceURI); } return false; } default:{ DOMNode *ancestor = getElementAncestor(thisNode); if (ancestor != 0) { return ancestor->isDefaultNamespace(namespaceURI); } return false; } } } DOMNode* DOMNodeImpl::getInterface(const XMLCh*) { throw DOMException(DOMException::NOT_SUPPORTED_ERR, 0, GetDOMNodeMemoryManager); return 0; } // non-standard extension void DOMNodeImpl::release() { // shouldn't reach here throw DOMException(DOMException::INVALID_ACCESS_ERR,0, GetDOMNodeMemoryManager); } XERCES_CPP_NAMESPACE_END