| /******************************************************************************* |
| * Copyright (c) 2000, 2003 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Common Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/cpl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.compare.examples.xml; |
| |
| import java.util.ArrayList; |
| import java.util.Vector; |
| |
| import org.eclipse.compare.rangedifferencer.IRangeComparator; |
| import org.eclipse.compare.rangedifferencer.RangeDifference; |
| import org.eclipse.compare.rangedifferencer.RangeDifferencer; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| |
| /** |
| * @version 1.0 |
| * @author |
| */ |
| public abstract class AbstractMatching { |
| |
| protected static final int NO_ENTRY = -1;//value with which fDT elements are initialized |
| protected static final String SIGN_ELEMENT= XMLStructureCreator.SIGN_ELEMENT; |
| int[][] fDT;//Distance Table; 1st index from fNLeft, 2nd index from fNRight |
| ArrayList[][] fDT_Matchings;//Mathing entries of children for a match. 1st index from fNLeft, 2nd index from fNRight |
| Vector fNLeft; |
| Vector fNRight; |
| Vector fMatches; |
| |
| /* methods used for match */ |
| |
| /* finds all the leaves of a tree and puts them in a vector */ |
| protected void findLeaves(XMLNode root, ArrayList leaves) { |
| if (isLeaf(root)) { |
| leaves.add(root); |
| } else { |
| Object[] children = root.getChildren(); |
| for (int i=0; i<children.length; i++) |
| findLeaves((XMLNode) children[i], leaves); |
| } |
| } |
| |
| /* true if x is a leaf */ |
| protected boolean isLeaf(XMLNode x) { |
| if (x == null) return true; |
| return x.getChildren() == null || x.getChildren().length <= 0; |
| } |
| |
| /* Numbers all nodes of tree. The number of x is its index in the vector numbering */ |
| protected void numberNodes(XMLNode root, Vector numbering) { |
| if (root != null) { |
| numbering.add(root); |
| Object[] children = root.getChildren(); |
| if (children != null) { |
| for (int i=0; i<children.length; i++) |
| numberNodes((XMLNode) children[i], numbering); |
| } |
| } |
| } |
| |
| /* counts # of nodes in tree including root */ |
| protected int countNodes(XMLNode root) { |
| if (root == null) return 0; |
| int count = 1; |
| if (isLeaf(root)) return count; |
| Object[] children = root.getChildren(); |
| for (int i=0; i<children.length; i++) |
| count+=countNodes((XMLNode) children[i]); |
| return count; |
| } |
| |
| /* returns index of node x in fNLeft */ |
| protected int indexOfLN (XMLNode x) { |
| int i; |
| for (i=0; (i<fNLeft.size()) && (fNLeft.elementAt(i) != x); i++); |
| return i; |
| } |
| |
| /* returns index of node y in fNRight */ |
| protected int indexOfRN (XMLNode y) { |
| int j; |
| for (j=0; (j<fNRight.size()) && (fNRight.elementAt(j) != y); j++); |
| return j; |
| } |
| |
| /* for testing */ |
| public Vector getMatches() { |
| return fMatches; |
| } |
| |
| protected class XMLComparator implements IRangeComparator { |
| |
| private Object[] fXML_elements; |
| |
| public XMLComparator(Object[] xml_elements) { |
| fXML_elements= xml_elements; |
| } |
| |
| /* |
| * @see IRangeComparator#getRangeCount() |
| */ |
| public int getRangeCount() { |
| return fXML_elements.length; |
| } |
| |
| /* |
| * @see IRangeComparator#rangesEqual(int, IRangeComparator, int) |
| */ |
| public boolean rangesEqual( |
| int thisIndex, |
| IRangeComparator other_irc, |
| int otherIndex) { |
| |
| if (other_irc instanceof XMLComparator) { |
| XMLComparator other= (XMLComparator) other_irc; |
| //return ((XMLNode)fXML_elements[thisIndex]).subtreeEquals(other.getXML_elements()[otherIndex]); |
| |
| //ordered compare of subtrees |
| //boolean result= ((XMLNode)fXML_elements[thisIndex]).subtreeEquals(other.getXML_elements()[otherIndex]); |
| |
| //taking ids into account |
| boolean sameId= false; |
| XMLNode thisNode= (XMLNode)fXML_elements[thisIndex]; |
| XMLNode otherNode= (XMLNode)other.getXML_elements()[otherIndex]; |
| if ( thisNode.usesIDMAP() && otherNode.usesIDMAP() ) { |
| if ( otherNode.getOrigId().equals(thisNode.getOrigId()) ) { |
| sameId= true; |
| } |
| } |
| |
| //unordered compare of subtrees |
| int distance= dist((XMLNode)other.getXML_elements()[otherIndex] , (XMLNode)fXML_elements[thisIndex]); |
| return sameId || distance == 0; |
| } |
| return false; |
| } |
| |
| /* |
| * @see IRangeComparator#skipRangeComparison(int, int, IRangeComparator) |
| */ |
| public boolean skipRangeComparison( |
| int length, |
| int maxLength, |
| IRangeComparator other) { |
| return false; |
| } |
| |
| public Object[] getXML_elements() { |
| return fXML_elements; |
| } |
| |
| } |
| |
| /* represents a matching between a node in the Left tree and a node in the Right tree */ |
| class Match { |
| public XMLNode fx; |
| public XMLNode fy; |
| |
| Match(XMLNode x, XMLNode y) { |
| fx = x; |
| fy = y; |
| } |
| |
| public boolean equals(Object obj) { |
| if (obj instanceof Match) { |
| Match m = (Match) obj; |
| if (m != null) |
| return fx == m.fx && fy == m.fy; |
| } |
| return false; |
| } |
| } |
| |
| protected int handleRangeDifferencer(Object[] xc_elements, Object[] yc_elements, ArrayList DTMatching, int distance) { |
| RangeDifference[] differences= RangeDifferencer.findDifferences(new XMLComparator(xc_elements), new XMLComparator(yc_elements)); |
| |
| int cur_pos_left= 0; |
| int cur_pos_right= 0; |
| for (int i= 0; i < differences.length; i++) { |
| RangeDifference rd= differences[i]; |
| int equal_length= rd.leftStart(); |
| //handle elements before current range which are unchanged |
| while (cur_pos_left < equal_length) { |
| //assuming XMLComparator has already filled fDT and fDT_Matchings for subtrees |
| //rooted at xc_elements[cur_pos_left] and yc_elements[cur_pos_right] |
| // if ( fDT[indexOfLN( (XMLNode)xc_elements[cur_pos_left])][indexOfRN( (XMLNode)yc_elements[cur_pos_right])] != 0) |
| // System.out.println("distance not 0"); |
| // distance += fDT[indexOfLN( (XMLNode)xc_elements[cur_pos_left])][indexOfRN( (XMLNode)yc_elements[cur_pos_right])]; |
| //DTMatching.addAll(fDT_Matchings[index_left][index_right]); |
| DTMatching.add(new Match( (XMLNode)xc_elements[cur_pos_left], (XMLNode)yc_elements[cur_pos_right])); |
| cur_pos_left++; |
| cur_pos_right++; |
| } |
| //now handle RangeDifference rd[i] |
| int smaller_length, greater_length; |
| boolean leftGreater= rd.leftLength() > rd.rightLength(); |
| if (leftGreater) { |
| smaller_length= rd.rightLength(); |
| greater_length= rd.leftLength(); |
| } else { |
| smaller_length= rd.leftLength(); |
| greater_length= rd.rightLength(); |
| } |
| |
| //handle elements elements in range |
| for (int j=0; j < smaller_length; j++) { |
| distance += dist((XMLNode) xc_elements[cur_pos_left], (XMLNode) yc_elements[cur_pos_right]); |
| DTMatching.add(new Match( (XMLNode)xc_elements[cur_pos_left], (XMLNode)yc_elements[cur_pos_right])); |
| cur_pos_left++; |
| cur_pos_right++; |
| } |
| //int cur_pos_greater= (leftGreater)?cur_pos_left:cur_pos_right; |
| if (leftGreater) { |
| for (int j=smaller_length; j < greater_length; j++) { |
| distance += countNodes((XMLNode) xc_elements[cur_pos_left]); |
| DTMatching.add(new Match( (XMLNode)xc_elements[cur_pos_left], null)); |
| cur_pos_left++; |
| } |
| } else { |
| for (int j=smaller_length; j < greater_length; j++) { |
| distance += countNodes((XMLNode) yc_elements[cur_pos_right]); |
| DTMatching.add(new Match( null, (XMLNode)yc_elements[cur_pos_right])); |
| cur_pos_right++; |
| } |
| } |
| // for (int j=smaller_length; j < greater_length; j++) { |
| // distance += countNodes((XMLNode) xc_elements[cur_pos_greater]); |
| // cur_pos_greater++; |
| // } |
| // if (leftGreater) |
| // cur_pos_left= cur_pos_greater; |
| // else |
| // cur_pos_right= cur_pos_greater; |
| } |
| |
| for (int i= cur_pos_left; i < xc_elements.length; i++) { |
| //distance += fDT[indexOfLN( (XMLNode)xc_elements[cur_pos_left])][indexOfRN( (XMLNode)yc_elements[cur_pos_right])]; |
| //DTMatching.addAll(fDT_Matchings[index_left][index_right]); |
| DTMatching.add(new Match( (XMLNode)xc_elements[cur_pos_left], (XMLNode)yc_elements[cur_pos_right])); |
| cur_pos_left++; |
| cur_pos_right++; |
| } |
| |
| return distance; |
| } |
| |
| abstract public void match(XMLNode LeftTree, XMLNode RightTree, boolean rightTreeIsAncestor, IProgressMonitor monitor) throws InterruptedException; |
| |
| protected int dist(XMLNode x, XMLNode y) { |
| //System.out.println("dist( "+x.getSignature()+" , "+y.getSignature()+")"); |
| int ret= NO_ENTRY; |
| |
| int index_x= indexOfLN(x); |
| int index_y= indexOfRN(y); |
| if (fDT[index_x][index_y] != NO_ENTRY) return fDT[index_x][index_y]; |
| |
| if (isLeaf(x) && isLeaf(y)) { |
| if (x.getXMLType() == XMLStructureCreator.TYPE_ELEMENT) { |
| if ( x.getSignature().equals(y.getSignature()) ) { |
| ret= 0; |
| fDT[index_x][index_y] = ret; |
| return ret; |
| } else { |
| ret= 2; |
| fDT[index_x][index_y] = ret; |
| return ret; |
| } |
| } else if (x.getXMLType() == XMLStructureCreator.TYPE_ATTRIBUTE || x.getXMLType() == XMLStructureCreator.TYPE_TEXT) { |
| if ( x.getSignature().equals(y.getSignature()) ) { |
| if (x.getValue().equals(y.getValue())) { |
| ret= 0; |
| fDT[index_x][index_y] = ret; |
| return ret; |
| } else { |
| ret= 1; |
| fDT[index_x][index_y] = ret; |
| return ret; |
| } |
| } |
| else { |
| ret= 2; |
| fDT[index_x][index_y] = ret; |
| return ret; |
| } |
| } |
| } else {//x or y are not leaves |
| if ( !x.getSignature().equals(y.getSignature()) ) { |
| ret= countNodes(x) + countNodes(y); |
| fDT[index_x][index_y] = ret; |
| return ret; |
| } else {//x.getSignature().equals(y.getSignature()) |
| if (isLeaf(x)) { |
| ret= countNodes(y)-1; |
| fDT[index_x][index_y] = ret; |
| return ret; |
| } |
| if (isLeaf(y)) { |
| ret= countNodes(x)-1; |
| fDT[index_x][index_y] = ret; |
| return ret; |
| } |
| //both x and y have children |
| return handleXandYnotLeaves(x,y); |
| } |
| } |
| return ret; |
| } |
| |
| abstract int handleXandYnotLeaves(XMLNode x, XMLNode y); |
| } |