Esempio n. 1
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"?
    //     <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.

    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;

}
Esempio n. 2
0
short            DOMNodeImpl::compareDocumentPosition(const DOMNode* other) const {
    DOMNode* thisNode = castToNode(this);

    // If the two nodes being compared are the same node, then no flags are set on the return.
    if (thisNode == other)
        return 0;

    //if this is a custom node, we don't really know what to do, just return
    //user should provide its own compareDocumentPosition logic, and shouldn't reach here
    if(thisNode->getNodeType() > 12) {
        return 0;
    }

    //if it is a custom node we must ask it for the order
    if(other->getNodeType() > 12) {
        return reverseTreeOrderBitPattern(other->compareDocumentPosition(thisNode));
    }

    // Otherwise, the order of two nodes is determined by looking for common containers --
    // containers which contain both. A node directly contains any child nodes.
    // A node also directly contains any other nodes attached to it such as attributes
    // contained in an element or entities and notations contained in a document type.
    // Nodes contained in contained nodes are also contained, but less-directly as
    // the number of intervening containers increases.

    // If one of the nodes being compared contains the other node, then the container precedes
    // the contained node, and reversely the contained node follows the container. For example,
    // when comparing an element against its own attribute or child, the element node precedes
    // its attribute node and its child node, which both follow it.

    const DOMNode* tmpNode;
    const DOMNode* myRoot = castToNode(this);
    int myDepth=0;
    while((tmpNode=getTreeParentNode(myRoot))!=0)
    {
        myRoot=tmpNode;
        if(myRoot==other)
            return DOMNode::DOCUMENT_POSITION_CONTAINS | DOMNode::DOCUMENT_POSITION_PRECEDING;
        myDepth++;
    }

    const DOMNode* hisRoot = other;
    int hisDepth=0;
    while((tmpNode=getTreeParentNode(hisRoot))!=0)
    {
        hisRoot=tmpNode;
        if(hisRoot==thisNode)
            return DOMNode::DOCUMENT_POSITION_CONTAINED_BY | DOMNode::DOCUMENT_POSITION_FOLLOWING;
        hisDepth++;
    }

    // If there is no common container node, then the order is based upon order between the
    // root container of each node that is in no container. In this case, the result is
    // disconnected and implementation-specific. This result is stable as long as these
    // outer-most containing nodes remain in memory and are not inserted into some other
    // containing node. This would be the case when the nodes belong to different documents
    // or fragments, and cloning the document or inserting a fragment might change the order.

    if(myRoot!=hisRoot)
        return DOMNode::DOCUMENT_POSITION_DISCONNECTED | DOMNode::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC |
              (myRoot<hisRoot?DOMNode::DOCUMENT_POSITION_PRECEDING:DOMNode::DOCUMENT_POSITION_FOLLOWING);

    // If neither of the previous cases apply, then there exists a most-direct container common
    // to both nodes being compared. In this case, the order is determined based upon the two
    // determining nodes directly contained in this most-direct common container that either
    // are or contain the corresponding nodes being compared.

    // if the two depths are different, go to the same one
    myRoot = castToNode(this);
    hisRoot = other;
    if (myDepth > hisDepth) {
        for (int i= 0 ; i < myDepth - hisDepth; i++)
            myRoot = getTreeParentNode(myRoot);
    }
    else {
        for (int i = 0; i < hisDepth - myDepth; i++)
            hisRoot = getTreeParentNode(hisRoot);
    }

    // We now have nodes at the same depth in the tree.  Find a common ancestor.
    const DOMNode *myNodeP=myRoot;
	const DOMNode *hisNodeP=hisRoot;
    while(myRoot!=hisRoot)
    {
        myNodeP = myRoot;
        hisNodeP = hisRoot;
        myRoot = getTreeParentNode(myRoot);
        hisRoot = getTreeParentNode(hisRoot);
    }

    short myNodeType=myNodeP->getNodeType();
    short hisNodeType=hisNodeP->getNodeType();
    bool bMyNodeIsChild=(myNodeType!=DOMNode::ATTRIBUTE_NODE && myNodeType!=DOMNode::ENTITY_NODE && myNodeType!=DOMNode::NOTATION_NODE);
    bool bHisNodeIsChild=(hisNodeType!=DOMNode::ATTRIBUTE_NODE && hisNodeType!=DOMNode::ENTITY_NODE && hisNodeType!=DOMNode::NOTATION_NODE);

    // If these two determining nodes are both child nodes, then the natural DOM order of these
    // determining nodes within the containing node is returned as the order of the corresponding nodes.
    // This would be the case, for example, when comparing two child elements of the same element.
    if(bMyNodeIsChild && bHisNodeIsChild)
    {
        while(myNodeP != 0)
        {
            myNodeP = myNodeP->getNextSibling();
            if(myNodeP == hisNodeP)
                return DOMNode::DOCUMENT_POSITION_FOLLOWING;
        }
        return DOMNode::DOCUMENT_POSITION_PRECEDING;
    }

    // If one of the two determining nodes is a child node and the other is not, then the corresponding
    // node of the child node follows the corresponding node of the non-child node. This would be the case,
    // for example, when comparing an attribute of an element with a child element of the same element.
    else if(!bMyNodeIsChild && bHisNodeIsChild)
        return DOMNode::DOCUMENT_POSITION_FOLLOWING;
    else if(bMyNodeIsChild && !bHisNodeIsChild)
        return DOMNode::DOCUMENT_POSITION_PRECEDING;

    else
    {
        // If neither of the two determining node is a child node and one determining node has a greater value
        // of nodeType than the other, then the corresponding node precedes the other. This would be the case,
        // for example, when comparing an entity of a document type against a notation of the same document type.
        if(myNodeType!=hisNodeType)
            return (myNodeType<hisNodeType)?DOMNode::DOCUMENT_POSITION_FOLLOWING:DOMNode::DOCUMENT_POSITION_PRECEDING;

        // If neither of the two determining node is a child node and nodeType is the same for both determining
        // nodes, then an implementation-dependent order between the determining nodes is returned. This order
        // is stable as long as no nodes of the same nodeType are inserted into or removed from the direct container.
        // This would be the case, for example, when comparing two attributes of the same element, and inserting
        // or removing additional attributes might change the order between existing attributes.
        return DOMNode::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC | ((myNodeP<hisNodeP)?DOMNode::DOCUMENT_POSITION_FOLLOWING:DOMNode::DOCUMENT_POSITION_PRECEDING);
    }
    // REVISIT:  shouldn't get here.   Should probably throw an
    // exception
    return 0;
}