public short compareDocumentPosition()

in src/org/apache/xerces/dom/NodeImpl.java [973:1235]


    public short compareDocumentPosition(Node other) throws DOMException {

        // If the nodes are the same, no flags should be set
        if (this==other) 
          return 0; 

        // check if other is from a different implementation
        if (other != null && !(other instanceof NodeImpl)) {
            // other comes from a different implementation
            String msg = DOMMessageFormatter.formatMessage(
               DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null);
            throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
        }

        Document thisOwnerDoc, otherOwnerDoc;
        // get the respective Document owners.  
        if (this.getNodeType() == Node.DOCUMENT_NODE) 
          thisOwnerDoc = (Document)this;
        else
          thisOwnerDoc = this.getOwnerDocument();
        if (other.getNodeType() == Node.DOCUMENT_NODE) 
          otherOwnerDoc = (Document)other;
        else
          otherOwnerDoc = other.getOwnerDocument();

        // If from different documents, we know they are disconnected. 
        // and have an implementation dependent order 
        if (thisOwnerDoc != otherOwnerDoc && 
            thisOwnerDoc !=null && 
            otherOwnerDoc !=null) 
 {
          int otherDocNum = ((CoreDocumentImpl)otherOwnerDoc).getNodeNumber();
          int thisDocNum = ((CoreDocumentImpl)thisOwnerDoc).getNodeNumber();
          if (otherDocNum > thisDocNum)  
            return DOCUMENT_POSITION_DISCONNECTED | 
                   DOCUMENT_POSITION_FOLLOWING | 
                   DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
          else
            return DOCUMENT_POSITION_DISCONNECTED | 
                   DOCUMENT_POSITION_PRECEDING | 
                   DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
                  
        }
     
        // 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. 

        Node node; 
        Node thisAncestor = this;
        Node otherAncestor = other;
       
        int thisDepth=0;
        int otherDepth=0;
        for (node=this; node != null; node = node.getParentNode()) {
            thisDepth +=1;
            if (node == other) 
              // The other node is an ancestor of this one.
              return (DOCUMENT_POSITION_CONTAINS | 
                      DOCUMENT_POSITION_PRECEDING);
            thisAncestor = node;
        }

        for (node=other; node!=null; node=node.getParentNode()) {
            otherDepth +=1;
            if (node == this) 
              // The other node is a descendent of the reference node.
              return (DOCUMENT_POSITION_IS_CONTAINED | 
                      DOCUMENT_POSITION_FOLLOWING);
            otherAncestor = node;
        }
        
       

        int thisAncestorType = thisAncestor.getNodeType();
        int otherAncestorType = otherAncestor.getNodeType();
        Node thisNode = this;
        Node otherNode = other;

        // Special casing for ENTITY, NOTATION, DOCTYPE and ATTRIBUTES
        // LM:  should rewrite this.                                          
        switch (thisAncestorType) {
          case Node.NOTATION_NODE:
          case Node.ENTITY_NODE: {
            DocumentType container = thisOwnerDoc.getDoctype();
            if (container == otherAncestor) return 
                   (DOCUMENT_POSITION_CONTAINS | DOCUMENT_POSITION_PRECEDING);
            switch (otherAncestorType) {
              case Node.NOTATION_NODE: 
              case Node.ENTITY_NODE:  {
                if (thisAncestorType != otherAncestorType) 
                 // the nodes are of different types
                 return ((thisAncestorType>otherAncestorType) ? 
                    DOCUMENT_POSITION_PRECEDING:DOCUMENT_POSITION_FOLLOWING);
                else {
                 // the nodes are of the same type.  Find order.
                 if (thisAncestorType == Node.NOTATION_NODE)
                 
                     if (((NamedNodeMapImpl)container.getNotations()).precedes(otherAncestor,thisAncestor))
                       return (DOCUMENT_POSITION_PRECEDING | 
                               DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC);
                     else
                       return (DOCUMENT_POSITION_FOLLOWING | 
                               DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC);
                 else
                     if (((NamedNodeMapImpl)container.getEntities()).precedes(otherAncestor,thisAncestor))
                       return (DOCUMENT_POSITION_PRECEDING | 
                               DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC);
                     else
                       return (DOCUMENT_POSITION_FOLLOWING | 
                               DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC);
                }
              }
            }
            thisNode = thisAncestor = thisOwnerDoc;
            break;
          } 
          case Node.DOCUMENT_TYPE_NODE: {
            if (otherNode == thisOwnerDoc) 
              return (DOCUMENT_POSITION_PRECEDING | 
                      DOCUMENT_POSITION_CONTAINS);
            else if (thisOwnerDoc!=null && thisOwnerDoc==otherOwnerDoc)
              return (DOCUMENT_POSITION_FOLLOWING);
            break;
          }
          case Node.ATTRIBUTE_NODE: {
            thisNode = ((AttrImpl)thisAncestor).getOwnerElement();
            if (otherAncestorType==Node.ATTRIBUTE_NODE) {
              otherNode = ((AttrImpl)otherAncestor).getOwnerElement();
              if (otherNode == thisNode) {
                if (((NamedNodeMapImpl)thisNode.getAttributes()).precedes(other,this))
                  return (DOCUMENT_POSITION_PRECEDING | 
                          DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC);
                else
                  return (DOCUMENT_POSITION_FOLLOWING | 
                          DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC);
              }
            }

            // Now, find the ancestor of the element
            thisDepth=0;
            for (node=thisNode; node != null; node=node.getParentNode()) {
                thisDepth +=1;
                if (node == otherNode) 
                  {
                  // The other node is an ancestor of the owning element
                  return (DOCUMENT_POSITION_CONTAINS | 
                          DOCUMENT_POSITION_PRECEDING);
                  }
                thisAncestor = node;
            }
          }
        }
        switch (otherAncestorType) {
          case Node.NOTATION_NODE:
          case Node.ENTITY_NODE: {
          DocumentType container = thisOwnerDoc.getDoctype();
            if (container == this) return (DOCUMENT_POSITION_IS_CONTAINED | 
                                          DOCUMENT_POSITION_FOLLOWING);
            otherNode = otherAncestor = thisOwnerDoc;
            break;
          }
          case Node.DOCUMENT_TYPE_NODE: {
            if (thisNode == otherOwnerDoc) 
              return (DOCUMENT_POSITION_FOLLOWING | 
                      DOCUMENT_POSITION_IS_CONTAINED);
            else if (otherOwnerDoc!=null && thisOwnerDoc==otherOwnerDoc)
              return (DOCUMENT_POSITION_PRECEDING);
            break;
          }
          case Node.ATTRIBUTE_NODE: {
            otherDepth=0;
            otherNode = ((AttrImpl)otherAncestor).getOwnerElement();
            for (node=otherNode; node != null; node=node.getParentNode()) {
                otherDepth +=1;
                if (node == thisNode) 
                  // The other node is a descendent of the reference 
                  // node's element
                  return DOCUMENT_POSITION_FOLLOWING | 
                         DOCUMENT_POSITION_IS_CONTAINED;
                otherAncestor = node;
            }

          }
        }
 
        // thisAncestor and otherAncestor must be the same at this point,  
        // otherwise, the original nodes are disconnected 
        if (thisAncestor != otherAncestor) {
          int thisAncestorNum, otherAncestorNum;
          thisAncestorNum = ((NodeImpl)thisAncestor).getNodeNumber();
          otherAncestorNum = ((NodeImpl)otherAncestor).getNodeNumber();
          
          if (thisAncestorNum > otherAncestorNum) 
            return DOCUMENT_POSITION_DISCONNECTED | 
                   DOCUMENT_POSITION_FOLLOWING | 
                   DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
          else
            return DOCUMENT_POSITION_DISCONNECTED | 
                   DOCUMENT_POSITION_PRECEDING | 
                   DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
        }

      
        // Go up the parent chain of the deeper node, until we find a node 
        // with the same depth as the shallower node

        if (thisDepth > otherDepth) {
          for (int i=0; i<thisDepth - otherDepth; i++)
            thisNode = thisNode.getParentNode();
          // Check if the node we have reached is in fact "otherNode". This can
          // happen in the case of attributes.  In this case, otherNode 
          // "precedes" this.
          if (thisNode == otherNode) 
{
            return DOCUMENT_POSITION_PRECEDING;
          }
        }
 
        else {
          for (int i=0; i<otherDepth - thisDepth; i++)
            otherNode = otherNode.getParentNode();
          // Check if the node we have reached is in fact "thisNode".  This can
          // happen in the case of attributes.  In this case, otherNode 
          // "follows" this.
          if (otherNode == thisNode) 
            return DOCUMENT_POSITION_FOLLOWING;
        }
             
        // We now have nodes at the same depth in the tree.  Find a common 
        // ancestor.                                   
        Node thisNodeP, otherNodeP;
        for (thisNodeP=thisNode.getParentNode(),
                  otherNodeP=otherNode.getParentNode();
             thisNodeP!=otherNodeP;) {
             thisNode = thisNodeP;
             otherNode = otherNodeP;
             thisNodeP = thisNodeP.getParentNode();
             otherNodeP = otherNodeP.getParentNode();
        }

        // At this point, thisNode and otherNode are direct children of 
        // the common ancestor.  
        // See whether thisNode or otherNode is the leftmost

        for (Node current=thisNodeP.getFirstChild(); 
                  current!=null;
                  current=current.getNextSibling()) {
               if (current==otherNode) {
                 return DOCUMENT_POSITION_PRECEDING;
               }
               else if (current==thisNode) {
                 return DOCUMENT_POSITION_FOLLOWING;
               }
        }
        // REVISIT:  shouldn't get here.   Should probably throw an 
        // exception
        return 0;

    }