package tools.xml; | |
import org.apache.xmlbeans.impl.common.QNameHelper; | |
import org.apache.xmlbeans.impl.common.XmlWhitespace; | |
import org.apache.xmlbeans.XmlObject; | |
import org.apache.xmlbeans.XmlCursor; | |
import org.apache.xmlbeans.XmlException; | |
/** | |
* Author: Cezar Andrei (cezar.andrei at bea.com) | |
* Date: Oct 30, 2003 | |
* @ignore true | |
*/ | |
public class XmlComparator | |
{ | |
public static class Diagnostic | |
{ | |
private StringBuffer message = null; | |
private void add(String s) | |
{ | |
if (message==null) | |
message = new StringBuffer(); | |
message.append(s).append("\n"); | |
} | |
public boolean hasMessage() | |
{ | |
return message!=null; | |
} | |
public String toString() | |
{ | |
return (message==null ? null : message.toString()); | |
} | |
public static void add(Diagnostic diag, String s) | |
{ | |
if ( diag!=null) | |
diag.add(s); | |
} | |
} | |
public static boolean wsCollapseEqual(String s1, String s2) | |
{ | |
String s1c = XmlWhitespace.collapse(s1); | |
String s2c = XmlWhitespace.collapse(s2); | |
return (s1c.equals(s2c)); | |
} | |
public static boolean compareNamesAndAttributes(XmlCursor cur1, XmlCursor cur2, Diagnostic diag) | |
{ | |
if (!cur1.getName().equals(cur2.getName())) | |
{ | |
Diagnostic.add(diag, "Element names " + QNameHelper.pretty(cur1.getName()) + " and " + QNameHelper.pretty(cur2.getName()) + " do not match"); | |
return false; | |
} | |
boolean more = cur1.toFirstAttribute(); | |
if (more) | |
{ | |
for (; more; more = cur1.toNextAttribute()) | |
{ | |
String text1 = cur1.getTextValue(); | |
String text2 = cur2.getAttributeText(cur1.getName()); | |
if (text2 == null) | |
{ | |
Diagnostic.add(diag, "Attribute " + QNameHelper.pretty(cur1.getName()) + " not present"); | |
return false; | |
} | |
if (!wsCollapseEqual(text1, text2)) | |
{ | |
Diagnostic.add(diag, "Attribute values for " + QNameHelper.pretty(cur1.getName()) + " do not match"); | |
return false; | |
} | |
} | |
cur1.toParent(); | |
} | |
more = cur2.toFirstAttribute(); | |
if (more) | |
{ | |
for (; more; more = cur2.toNextAttribute()) | |
{ | |
String text1 = cur1.getAttributeText(cur2.getName()); | |
if (text1 == null) | |
{ | |
Diagnostic.add(diag, "Attribute " + QNameHelper.pretty(cur2.getName()) + " not present"); | |
return false; | |
} | |
} | |
cur2.toParent(); | |
} | |
return true; | |
} | |
public static Diagnostic lenientlyCompareTwoXmlStrings(String actual, String expect) | |
throws XmlException | |
{ | |
Diagnostic diag = new Diagnostic(); | |
lenientlyCompareTwoXmlStrings(actual, expect, diag); | |
return diag; | |
} | |
/** | |
* Provides an utility to compare the xml inside the two strings | |
* @return true if the xml inside the two strings is leniently the same | |
* otherwise false | |
*/ | |
public static boolean lenientlyCompareTwoXmlStrings(String actual, String expect, Diagnostic diag) | |
throws XmlException | |
{ | |
XmlObject xobj1 = XmlObject.Factory.parse(actual); | |
XmlObject xobj2 = XmlObject.Factory.parse(expect); | |
XmlCursor cur1 = xobj1.newCursor(); | |
XmlCursor cur2 = xobj2.newCursor(); | |
cur1.toFirstChild(); | |
cur2.toFirstChild(); | |
return lenientlyCompareTwoXmlStrings(cur1, cur2, diag); | |
} | |
/** | |
* Provides an utility to compare the xml inside the two cursors | |
* @return true if the xml inside the two strings is leniently the same | |
* otherwise false | |
*/ | |
public static boolean lenientlyCompareTwoXmlStrings(XmlCursor cur1, XmlCursor cur2, Diagnostic diag) | |
{ | |
boolean match = true; | |
int depth = 0; | |
while (cur1.currentTokenType() != XmlCursor.TokenType.STARTDOC) | |
{ | |
if (!compareNamesAndAttributes(cur1, cur2, diag)) | |
{ | |
match = false; | |
} | |
boolean hasChildren1 = cur1.toFirstChild(); | |
boolean hasChildren2 = cur2.toFirstChild(); | |
depth++; | |
if (hasChildren1 != hasChildren2) | |
{ | |
Diagnostic.add(diag, "Topology differs: one document has children where the other does not (" + QNameHelper.pretty(cur1.getName()) + ", " + QNameHelper.pretty(cur2.getName()) + ")"); // TODO: where? | |
match = false; | |
if (hasChildren1) | |
{ | |
cur1.toParent(); | |
hasChildren1 = false; | |
} | |
if (hasChildren2) | |
{ | |
cur2.toParent(); | |
hasChildren2 = false; | |
} | |
} | |
else if (hasChildren1 == false) | |
{ | |
if (!wsCollapseEqual(cur1.getTextValue(), cur2.getTextValue())) | |
{ | |
Diagnostic.add(diag, "Value " + cur1.getTextValue() + " differs from value " + cur2.getTextValue()); | |
match = false; | |
} | |
} | |
if (hasChildren1) | |
continue; | |
for (;;) | |
{ | |
boolean hasSibling1 = cur1.toNextSibling(); | |
boolean hasSibling2 = cur2.toNextSibling(); | |
if (hasSibling1 != hasSibling2) | |
{ | |
Diagnostic.add(diag, "Topology differs: one document has siblings where the other does not"); // TODO: where? | |
hasSibling1 = false; | |
hasSibling2 = false; | |
} | |
if (hasSibling1) | |
break; | |
cur1.toParent(); | |
cur2.toParent(); | |
depth--; | |
if (cur1.currentTokenType() == XmlCursor.TokenType.STARTDOC || depth<=0) | |
break; | |
} | |
} | |
return match; | |
} | |
} |