tng 2002/08/09 13:20:41 Modified: c/src/xercesc/dom/impl DOMNodeImpl.cpp DOMNodeImpl.hpp Log: DOM L3: support compareTreePosition. Patch from Gareth Reakes. Revision Changes Path 1.9 +222 -2 xml-xerces/c/src/xercesc/dom/impl/DOMNodeImpl.cpp Index: DOMNodeImpl.cpp =================================================================== RCS file: /home/cvs/xml-xerces/c/src/xercesc/dom/impl/DOMNodeImpl.cpp,v retrieving revision 1.8 retrieving revision 1.9 diff -u -r1.8 -r1.9 --- DOMNodeImpl.cpp 26 Jul 2002 16:35:16 -0000 1.8 +++ DOMNodeImpl.cpp 9 Aug 2002 20:20:41 -0000 1.9 @@ -65,6 +65,7 @@ #include "DOMDocumentTypeImpl.hpp" #include "DOMElementImpl.hpp" +#include "DOMAttrImpl.hpp" #include "DOMCasts.hpp" #include "DOMDocumentImpl.hpp" @@ -492,9 +493,228 @@ } short DOMNodeImpl::compareTreePosition(DOMNode* other){ - throw DOMException(DOMException::NOT_SUPPORTED_ERR, 0); + // 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"? + // <outer> + // <inner myattr="true"/> + // </outer> + // 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. + + DOMNode *node; + DOMNode *thisAncestor = castToNode(this); + 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; + } + + + 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; +} + const XMLCh* DOMNodeImpl::getTextContent() const{ return 0; 1.8 +3 -1 xml-xerces/c/src/xercesc/dom/impl/DOMNodeImpl.hpp Index: DOMNodeImpl.hpp =================================================================== RCS file: /home/cvs/xml-xerces/c/src/xercesc/dom/impl/DOMNodeImpl.hpp,v retrieving revision 1.7 retrieving revision 1.8 diff -u -r1.7 -r1.8 --- DOMNodeImpl.hpp 15 Jul 2002 19:22:22 -0000 1.7 +++ DOMNodeImpl.hpp 9 Aug 2002 20:20:41 -0000 1.8 @@ -168,6 +168,8 @@ void callUserDataHandlers(DOMUserDataHandler::DOMOperationType operation, const DOMNode* src, const DOMNode* dst) const; + //reverses the bit pattern given by compareTreePosition + short reverseTreeOrderBitPattern(short pattern) const; //Utility, not part of DOM Level 2 API
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]