using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml; namespace TradeIdeas.TIProGUI { //This class is copied *almost* verbatim from: // https://www.daniweb.com/software-development/csharp/threads/421857/comparing-xml-for-unit-testing // Kathy adds an additional test for the Column order (seen in data grid). Since this class from the above reference is // supposed to test for equality of two XML nodes regardless of order, the column order in TIPro is a // special case where the order is quite important-thus the order of the respective nodes are crucial. public class XMLComparer { /// /// Compares two xml documents for eqality as defined for this comparer. /// /// The first xml document. /// the second xml document. /// True if the documents are equal, otherwise false. public static bool AreEqualNoOrder(XmlDocument docA, XmlDocument docB) { return NodesAreEqualNoOrder(docA.FirstChild, docB.FirstChild); } /// /// Compares two nodes for equality as defined for this comparer. /// /// A node from the first document. /// a node from the second document. /// True if the nodes are equal, otherwise false. public static bool NodesAreEqualNoOrder(XmlNode nodeA, XmlNode nodeB) { /////////////// // Compare Text /////////////// var textA = nodeA.Name; var textB = nodeB.Name; if (textA == null || textB == null) { // if either is null, then they should both be null. if (!(textA == null && textB == null)) { return false; } } else { // if they are not null, the text should be the same if (!textA.Trim().Equals(textB.Trim())) { return false; } } ///////////////////// // Compare Attributes ///////////////////// var attributesA = nodeA.Attributes; var attributesB = nodeB.Attributes; if (attributesA == null || attributesB == null) { // if either is null, then they should both be null. if (!(attributesA == null && attributesB == null)) { return false; } } else { // if there are attributes, there should be the same number on A as on B. if (attributesB == null || attributesA.Count != attributesB.Count) { return false; } // check each attribute and value for (int i = 0; i < attributesA.Count; i++) { var name = attributesA[i].Name; // if nodeA has an attribute named x, then so should nodeB. if (attributesB[name] == null) { return false; } // if nodeA and nodeB both have attributes named x, they should have the same value. if (attributesB[name].Value != attributesA[name].Value) { return false; } } } ////////////////////// // Compare Child Nodes ////////////////////// var childsA = nodeA.ChildNodes; var childsB = nodeB.ChildNodes; // the number of children of nodeA should be the same as the number of childeren of nodeB. if (childsA.Count != childsB.Count) { return false; } if (nodeA.Name == "ORDER") { for (int i = 0; i < childsB.Count; i++) { string aTest = childsA[i].Attributes["CODE"].Value; string bTest = childsB[i].Attributes["CODE"].Value; if (aTest != bTest) { return false; } } } // every child of nodeA should have a matching child of nodeB, but not necessarily in the same order. while (childsA.Count > 0) { // look for a match in nodeB for the first child of nodeA var matchFound = false; for (int i = 0; i < childsB.Count; i++) { if (NodesAreEqualNoOrder(childsA[0], childsB[i])) { // if a match is found in nodeB, remove the child in nodeA and the match in nodeB, then move on. // this is important because if A had child nodes x and x and B had child nodes x and y, // then both A nodes would match, but B would have a y that wasn't found. matchFound = true; childsA[0].ParentNode.RemoveChild(childsA[0]); childsB[i].ParentNode.RemoveChild(childsB[i]); break; } } if (!matchFound) { // if no match is found, the nodes ain't the same. return false; } } // if no test failed, the nodes are equal. return true; } } }