in src/org/apache/xerces/dom/NodeImpl.java [971:1233]
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;
}