336 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			336 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using System;
 | |
| using System.Collections.Generic;
 | |
| using System.Linq;
 | |
| using System.Text;
 | |
| using System.Xml;
 | |
| using System.Windows.Forms;
 | |
| 
 | |
| namespace VEPROMS.CSLA.Library
 | |
| {
 | |
| 	public class Comparator
 | |
| 	{
 | |
| 		private XmlDocument _ResultsDoc;
 | |
| 		public XmlDocument ResultsDoc
 | |
| 		{
 | |
| 			get { return _ResultsDoc; }
 | |
| 			set { _ResultsDoc = value; }
 | |
| 		}
 | |
| 		private XmlDocument _XDoc1;
 | |
| 		public XmlDocument XDoc1
 | |
| 		{
 | |
| 			get { return _XDoc1; }
 | |
| 			set { _XDoc1 = value; }
 | |
| 		}
 | |
| 		private XmlDocument _XDoc2;
 | |
| 		public XmlDocument XDoc2
 | |
| 		{
 | |
| 			get { return _XDoc2; }
 | |
| 			set { _XDoc2 = value; }
 | |
| 		}
 | |
| 		public Comparator(XmlDocument xdoc1, XmlDocument xdoc2)
 | |
| 		{
 | |
| 			XDoc1 = xdoc1;
 | |
| 			XDoc2 = xdoc2;
 | |
| 			ResultsDoc = new XmlDocument();
 | |
| 			ResultsDoc.LoadXml(@"<PlantFormat></PlantFormat>");
 | |
| 		}
 | |
| 		public Comparator(string existingFC, string importedFC) //string fName1, string fName2)
 | |
| 		{
 | |
| 			XDoc1 = new XmlDocument();
 | |
| 			XDoc1.LoadXml(existingFC);
 | |
| 			XDoc2 = new XmlDocument();
 | |
| 			XDoc2.LoadXml(importedFC);
 | |
| 			ResultsDoc = new XmlDocument();
 | |
| 			ResultsDoc.LoadXml(@"<PlantFormat></PlantFormat>");
 | |
| 		}
 | |
| 		public XmlDocument Compare()
 | |
| 		{
 | |
| 			AllKeys = null;
 | |
| 			Compare(XDoc1.DocumentElement, XDoc2.DocumentElement, "");
 | |
| 			Console.WriteLine("results xml = \r\n{0}", ResultsDoc.InnerXml);
 | |
| 			return ResultsDoc;
 | |
| 		}
 | |
| 		public void Compare(XmlNode xn1, XmlNode xn2, string path)
 | |
| 		{
 | |
| 			if (xn1.OuterXml == xn2.OuterXml) return;
 | |
| 			Compare(xn1.Attributes, xn2.Attributes , path, xn1, xn2);
 | |
| 			xn1.Attributes.RemoveAll();
 | |
| 			xn2.Attributes.RemoveAll();
 | |
| 
 | |
| 			Dictionary<string, XmlNode> xns1 = new Dictionary<string, XmlNode>();		// child nodes, key = 'OuterXml', value = node itself 
 | |
| 			Dictionary<string, XmlNode> xns2 = new Dictionary<string, XmlNode>();	
 | |
| 			// xns1 starts out with all child nodes of xn1
 | |
| 			foreach (XmlNode xc1 in xn1.ChildNodes)
 | |
| 				xns1.Add(xc1.OuterXml + GetKey(xc1), xc1);
 | |
| 			// xns1 - remove any matching child nodes from xns2
 | |
| 			// xns2 - has nodes that are not in xns1
 | |
| 			foreach (XmlNode xc2 in xn2.ChildNodes)
 | |
| 				if (xns1.ContainsKey(xc2.OuterXml + GetKey(xc2)))
 | |
| 					xns1.Remove(xc2.OuterXml + GetKey(xc2));
 | |
| 				else
 | |
| 					xns2.Add(xc2.OuterXml+GetKey(xc2), xc2);
 | |
| 
 | |
| 			// xnss1 & xnss2 are dictionaries based on a unique key 
 | |
| 			Dictionary<string, XmlNode> xnss1 = new Dictionary<string, XmlNode>();
 | |
| 			Dictionary<string, XmlNode> xnss2 = new Dictionary<string, XmlNode>();
 | |
| 			foreach (XmlNode xc1 in xns1.Values)
 | |
| 				xnss1.Add(GetKey(xc1), xc1);
 | |
| 			foreach (XmlNode xc2 in xns2.Values)
 | |
| 				if (xnss1.ContainsKey(GetKey(xc2)))
 | |
| 					Compare(xnss1[GetKey(xc2)], xc2, path + "/" + GetKey(xc2));
 | |
| 				else
 | |
| 					xnss2.Add(GetKey(xc2), xc2);
 | |
| 			// element differences, if counts are different. xns1 elements are not found in xns2 and xns2 elements are not found in xns1
 | |
| 			if (xns1.Count == 0 && xns2.Count == 0) return;
 | |
| 			xns1 = new Dictionary<string, XmlNode>();		// child nodes, key = 'OuterXml', value = node itself 
 | |
| 			xns2 = new Dictionary<string, XmlNode>();
 | |
| 			// xns1 starts out with all child nodes of xn1
 | |
| 			foreach (XmlNode xc1 in xn1.ChildNodes)
 | |
| 			{
 | |
| 				xns1.Add(xc1.OuterXml+GetKey(xc1), xc1);
 | |
| 			}
 | |
| 			// xns1 - remove any matching child nodes from xns2
 | |
| 			// xns2 - has nodes that are not in xns1
 | |
| 			foreach (XmlNode xc2 in xn2.ChildNodes)
 | |
| 				if (xns1.ContainsKey(xc2.OuterXml + GetKey(xc2)))
 | |
| 					xns1.Remove(xc2.OuterXml + GetKey(xc2));
 | |
| 				else
 | |
| 					xns2.Add(xc2.OuterXml + GetKey(xc2), xc2);
 | |
| 
 | |
| 			// xnss1 & xnss2 are dictionaries based on a unique key 
 | |
| 			xnss1 = new Dictionary<string, XmlNode>();
 | |
| 			xnss2 = new Dictionary<string, XmlNode>();
 | |
| 			foreach (XmlNode xc1 in xns1.Values)
 | |
| 				xnss1.Add(GetKey(xc1), xc1);
 | |
| 			foreach (XmlNode xc2 in xns2.Values)
 | |
| 				if (xnss1.ContainsKey(GetKey(xc2)))
 | |
| 					Compare(xnss1[GetKey(xc2)], xc2, path + "/" + GetKey(xc2));
 | |
| 				else
 | |
| 					xnss2.Add(GetKey(xc2), xc2);
 | |
| 			// element differences, if counts are different. xns1 elements are not found in xns2 and xns2 elements are not found in xns1
 | |
| 			if (xns1.Count == 0 && xns2.Count == 0) return;
 | |
| 			Console.WriteLine(" {0} {1} {2}", path + "/" + xn1.Name, xns1.Count, xns2.Count);
 | |
| 			foreach (string key in xnss1.Keys)
 | |
| 			{
 | |
| 				if (xnss1[key].Attributes.Count > 0 || xnss1[key].ChildNodes.Count > 0)
 | |
| 				{
 | |
| 					XmlNode xnr = MakeXPathFormat(path);
 | |
| 					if (xnr != null)
 | |
| 					{
 | |
| 						XmlNode cloned = xnss1[key].CloneNode(true);
 | |
| 						XmlNode importNode = ResultsDoc.ImportNode(cloned, true);
 | |
| 						XmlNode resnd = xnr.AppendChild(importNode);
 | |
| 						XmlAttribute xKey = ResultsDoc.CreateAttribute("Mode");
 | |
| 						xKey.Value = "Deleted";                                                                                                                                                                                                              
 | |
| 						resnd.Attributes.Append(xKey);
 | |
| 						xKey = ResultsDoc.CreateAttribute("OldKey");
 | |
| 						xKey.Value = GetKey(xnss1[key]);
 | |
| 						resnd.Attributes.Append(xKey);
 | |
| 						xnr.AppendChild(resnd);
 | |
| 						if (resnd.ChildNodes.Count > 0)
 | |
| 						{
 | |
| 							foreach (XmlNode cxn in resnd.ChildNodes) if (cxn.Name == "Layout") SuffixAttributes("Old", cxn);
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 				xnss1[key].ParentNode.RemoveChild(xnss1[key]);
 | |
| 			}
 | |
| 			
 | |
| 			foreach (string key in xnss2.Keys)
 | |
| 			{
 | |
| 				if (xnss2[key].Attributes.Count > 0 || xnss2[key].ChildNodes.Count > 0)
 | |
| 				{
 | |
| 					XmlNode xnr = MakeXPathFormat(path);
 | |
| 					if (xnr != null)
 | |
| 					{
 | |
| 						XmlNode cloned = xnss2[key].CloneNode(true);
 | |
| 						XmlNode importNode = ResultsDoc.ImportNode(cloned, true);
 | |
| 						XmlNode resnd = xnr.AppendChild(importNode);
 | |
| 						
 | |
| 						// if this has subnodes, add the 'Inserted' mode on them, otherwise, out it on this level
 | |
| 						if (resnd.ChildNodes.Count > 0)
 | |
| 						{
 | |
| 							foreach (XmlNode cxn in resnd.ChildNodes)
 | |
| 							{
 | |
| 								if (cxn.Name=="Layout")  SuffixAttributes("New", cxn);
 | |
| 								XmlAttribute xKey = ResultsDoc.CreateAttribute("Mode");
 | |
| 								xKey.Value = "Inserted";
 | |
| 								if (cxn is XmlText)
 | |
| 									resnd.Attributes.Append(xKey);
 | |
| 								else
 | |
| 									cxn.Attributes.Append(xKey);		// crashing here on a flag difference - trying to append this attribute to 'false'.
 | |
| 							}
 | |
| 						}
 | |
| 						else
 | |
| 						{
 | |
| 							XmlAttribute xKey = ResultsDoc.CreateAttribute("Mode");
 | |
| 							xKey.Value = "Inserted";
 | |
| 							resnd.Attributes.Append(xKey);
 | |
| 						}
 | |
| 						XmlAttribute xKey1 = ResultsDoc.CreateAttribute("NewKey");
 | |
| 						xKey1.Value = GetKey(xnss2[key]);
 | |
| 						resnd.Attributes.Append(xKey1);
 | |
| 						xnr.AppendChild(resnd);
 | |
| 					}
 | |
| 				}
 | |
| 				xnss2[key].ParentNode.RemoveChild(xnss2[key]);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		private void SuffixAttributes(string suffix, XmlNode resnd)
 | |
| 		{
 | |
| 			Dictionary<string, string> renameList = new Dictionary<string, string>();
 | |
| 			foreach (XmlAttribute xa in resnd.Attributes) renameList.Add(xa.Name, xa.Value);
 | |
| 			foreach (string key in renameList.Keys)
 | |
| 			{
 | |
| 				resnd.Attributes.RemoveNamedItem(key);
 | |
| 				XmlAttribute xKey1 = ResultsDoc.CreateAttribute(key+suffix);
 | |
| 				xKey1.Value = renameList[key];
 | |
| 				resnd.Attributes.Append(xKey1);
 | |
| 			}
 | |
| 		}
 | |
| 		private Dictionary<XmlNode, string> _AllKeys;
 | |
| 		public Dictionary<XmlNode, string> AllKeys
 | |
| 		{
 | |
| 			get 
 | |
| 			{
 | |
| 				if (_AllKeys == null) _AllKeys = new Dictionary<XmlNode, string>();
 | |
| 				return _AllKeys; 
 | |
| 			}
 | |
| 			set { _AllKeys = value; }
 | |
| 		}
 | |
| 		public string GetKey(XmlNode xn)
 | |
| 		{
 | |
| 			string key = GetKey1(xn);
 | |
| 			if (AllKeys.ContainsKey(xn)) return AllKeys[xn];
 | |
| 			AllKeys.Add(xn, key);
 | |
| 			return key;
 | |
| 		}
 | |
| 		// Get unique key, key is a string representing either the name itself or a combination of element name/attribute to make it unique
 | |
| 		public string GetKey1(XmlNode xn)
 | |
| 		{
 | |
| 			if (xn.Attributes == null) return xn.Name;
 | |
| 			XmlAttribute xi = xn.Attributes.GetNamedItem("Index") as XmlAttribute;
 | |
| 			if (xi != null)
 | |
| 			{
 | |
| 			XmlAttribute xa = xn.Attributes.GetNamedItem("Name") as XmlAttribute;
 | |
| 				if (xa != null) return string.Format("{0}[{1}]", xn.Name, xa.Value);
 | |
| 				return string.Format("{0}[{1}]", xn.Name, xi.Value);
 | |
| 			}
 | |
| 			XmlAttribute xt = xn.Attributes.GetNamedItem("Token") as XmlAttribute;
 | |
| 			if(xt != null) return string.Format("{0}[{1}]", xn.Name, xt.Value);
 | |
| 			XmlAttribute xw = xn.Attributes.GetNamedItem("ReplaceWord") as XmlAttribute;
 | |
| 			if(xw != null) return string.Format("{0}[{1}]", xn.Name, xw.Value);
 | |
| 			return xn.Name;
 | |
| 		}
 | |
| 		static private XmlNode makeXPath(XmlDocument doc, string xpath)
 | |
| 		{
 | |
| 			xpath = xpath.Replace(@"DocStyle[", @"DocStyle[@Name='");
 | |
| 			xpath = xpath.Replace(@"]", "']");
 | |
| 			return makeXPath(doc, doc as XmlNode, xpath);
 | |
| 		}
 | |
| 
 | |
| 		static private XmlNode makeXPath(XmlDocument doc, XmlNode parent, string xpath)
 | |
| 		{
 | |
| 			if (xpath.Contains("DocStyle")) Console.WriteLine("here");
 | |
| 			// grab the next node name in the xpath; or return parent if empty
 | |
| 			string[] partsOfXPath = xpath.Trim('/').Split('/');
 | |
| 			string nextNodeInXPath = partsOfXPath.First();
 | |
| 			if (string.IsNullOrEmpty(nextNodeInXPath))
 | |
| 				return parent;
 | |
| 
 | |
| 			XmlNode node = parent.SelectSingleNode(nextNodeInXPath);
 | |
| 			if (node == null)
 | |
| 			{
 | |
| 				if (nextNodeInXPath.Contains("@"))		// element with an attribute, create both
 | |
| 				{
 | |
| 					// make element
 | |
| 					string elename = nextNodeInXPath.Substring(0, nextNodeInXPath.IndexOf("@") - 1);
 | |
| 					node = parent.AppendChild(doc.CreateElement(elename));
 | |
| 					// make attribute
 | |
| 					int indx = nextNodeInXPath.IndexOf("@")+1;
 | |
| 					string name = nextNodeInXPath.Substring(indx, nextNodeInXPath.IndexOf("=",indx)-indx);
 | |
| 					XmlAttribute xKeyd = doc.CreateAttribute(name);
 | |
| 					indx = nextNodeInXPath.IndexOf("='",indx)+2;
 | |
| 					string value = nextNodeInXPath.Substring(indx,nextNodeInXPath.IndexOf("'", indx) - indx);
 | |
| 					xKeyd.Value = nextNodeInXPath.Substring(indx,nextNodeInXPath.IndexOf("'",indx)-indx);
 | |
| 					node.Attributes.Append(xKeyd);
 | |
| 				}
 | |
| 				else
 | |
| 					node = parent.AppendChild(doc.CreateElement(nextNodeInXPath));
 | |
| 			}
 | |
| 
 | |
| 			// rejoin the remainder of the array as an xpath expression and recurse
 | |
| 			string rest = String.Join("/", partsOfXPath.Skip(1).ToArray());
 | |
| 			return makeXPath(doc, node, rest);
 | |
| 		}
 | |
| 
 | |
| 		private XmlNode MakeXPathFormat(string xpath)
 | |
| 		{
 | |
| 			// first find or make, if not found, the XmlElement within FormatData or DocStyles
 | |
| 			Console.WriteLine("path = {0}", xpath);
 | |
| 			return makeXPath(ResultsDoc, xpath);
 | |
| 		}
 | |
| 		#region Attributes
 | |
| 		private void Compare(XmlAttributeCollection atts1, XmlAttributeCollection atts2, string path, XmlNode atts1Par, XmlNode atts2Par)
 | |
| 		{
 | |
| 			// go through attributes in first xml document, see if they exist in the 2nd xml document & are identical attribute
 | |
| 			foreach (XmlAttribute xa1 in atts1)	
 | |
| 			{
 | |
| 				XmlAttribute xa2 = atts2.GetNamedItem(xa1.Name) as XmlAttribute;
 | |
| 				if (xa2 == null)
 | |
| 				{
 | |
| 					XmlNode xnr = MakeXPathFormat(path);
 | |
| 					if (xnr != null)
 | |
| 					{
 | |
| 						XmlAttribute xKey = ResultsDoc.CreateAttribute(xa1.Name+"Old");
 | |
| 						xKey.Value = xa1.Value;
 | |
| 						xnr.Attributes.Append(xKey);
 | |
| 						xKey = ResultsDoc.CreateAttribute("OldKey");
 | |
| 						xKey.Value = GetKey(atts1Par);
 | |
| 						if (xKey.Value != null) xnr.Attributes.Append(xKey);
 | |
| 					}
 | |
| 				}
 | |
| 				else if (xa2.Value != xa1.Value)
 | |
| 				{
 | |
| 					XmlNode xnr = MakeXPathFormat(path);
 | |
| 					if (xnr != null)
 | |
| 					{
 | |
| 						XmlAttribute xKey = ResultsDoc.CreateAttribute(xa1.Name + "Old");
 | |
| 						xKey.Value = xa1.Value;
 | |
| 						xnr.Attributes.Append(xKey);
 | |
| 						XmlAttribute xKey2 = ResultsDoc.CreateAttribute(xa2.Name + "New");
 | |
| 						xKey2.Value = xa2.Value;
 | |
| 						xnr.Attributes.Append(xKey2);
 | |
| 						xKey = ResultsDoc.CreateAttribute("OldKey");
 | |
| 						xKey.Value = GetKey(atts1Par);
 | |
| 						if (xKey.Value != null) xnr.Attributes.Append(xKey);
 | |
| 						xKey = ResultsDoc.CreateAttribute("NewKey");
 | |
| 						xKey.Value = GetKey(atts2Par);
 | |
| 						if (xKey.Value != null) xnr.Attributes.Append(xKey);
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 			// go through attributes in 2nd xml document to see if they exist in the first xml document & are identical
 | |
| 			foreach (XmlAttribute xa2 in atts2)
 | |
| 			{
 | |
| 				XmlAttribute xa1 = atts1.GetNamedItem(xa2.Name) as XmlAttribute;
 | |
| 				if (xa1 == null)
 | |
| 				{
 | |
| 					XmlNode xnr = MakeXPathFormat(path);
 | |
| 					if (xnr != null)
 | |
| 					{
 | |
| 						XmlAttribute xKey = ResultsDoc.CreateAttribute(xa2.Name+"New");
 | |
| 						xKey.Value = xa2.Value;
 | |
| 						xnr.Attributes.Append(xKey);
 | |
| 						xKey = ResultsDoc.CreateAttribute("NewKey");
 | |
| 						xKey.Value = GetKey(atts2Par);
 | |
| 						if (xKey.Value != null) xnr.Attributes.Append(xKey);
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 		#endregion
 | |
| 	}
 | |
| }
 |