Beispiel #1
0
        public void Compare(Stream stream1, Stream stream2, IXmlCompareHandler callback)
        {
            var       stopWatch   = new Stopwatch();
            var       loadOptions = LoadOptions.SetBaseUri | LoadOptions.SetLineInfo;
            const int leftId      = 1;
            const int rightId     = 2;

            var doc1 = XDocument.Load(stream1, loadOptions);
            var doc2 = XDocument.Load(stream2, loadOptions);

            var nsm1 = new XmlNamespaceManagerEnhanced(doc1);
            var nsm2 = new XmlNamespaceManagerEnhanced(doc2);


            var doc1Descendants = doc1.Descendants()
                                  .Where(a => a != doc1.Root).Select(a => Elem.Create(a, leftId)).ToList();

            var doc2Descendants = doc2.Descendants()
                                  .Where(a => a != doc2.Root).Select(a => Elem.Create(a, rightId)).ToList();


            var xPathsAdded   = new List <string>();
            var xPathsRemoved = new List <string>();
            var xPathsChanged = new List <string>();



            stopWatch.Start();
            foreach (var item1 in doc1Descendants)
            {
                //taken same levels
                var levelCollection = doc2Descendants.Where(x => x.Level == item1.Level);
                //taken same parents
                var groupCollection = levelCollection.Where(x => XPathComparer.CompareParent(item1.XPath, x.XPath));
                //take matched children
                var itemCollection = groupCollection.Where(a => XPathComparer.Compare(item1.XPath, a.XPath)).ToList();

                //handle properties used in a list
                if (itemCollection.Count > 1)
                {
                    var isExist = false;
                    foreach (var prop in itemCollection)
                    {
                        if (item1.XPath == prop.XPath)
                        {
                            isExist        = true;
                            prop.isChecked = true;
                        }
                    }
                    if (!isExist)
                    {
                        xPathsChanged.Add(item1.XPath);
                        changes.Add(new ElementChangedEventArgs(item1.XPath, item1.Element, item1.Element.LineNumber(), item1.Element, item1.LineNumber));
                    }
                }
                else
                {
                    var item2 = itemCollection.FirstOrDefault();

                    if (!groupCollection.ToList().Any() && item2 == null) // group collection will be empty when parent property has changed
                    {
                        var changedParentCollection = levelCollection.Where(x => item1.XPath.CompareImmediateParent(x.XPath) && XPathComparer.Compare(item1.XPath, x.XPath));
                        var isPresent = changedParentCollection.Any();
                        if (isPresent)
                        {
                            changedParentCollection.ToList().ForEach(x => x.isChecked = true);
                            continue;
                        }
                        xPathsRemoved.Add(item1.XPath);
                        removals.Add(new ElementRemovedEventArgs(item1.XPath, item1.Element, item1.LineNumber));
                        continue;
                    }
                    if (item2 == null)
                    {
                        if (xPathsRemoved.Any(a => item1.XPath.StartsWith(a)))
                        {
                            continue;
                        }

                        xPathsRemoved.Add(item1.XPath);
                        removals.Add(new ElementRemovedEventArgs(item1.XPath, item1.Element, item1.LineNumber));
                        continue;
                    }
                    else if (item1.XPath != item2.XPath)
                    {
                        if (!xPathsChanged.Any(a => item1.XPath.StartsWith(a)))
                        {
                            xPathsChanged.Add(item1.XPath);
                            changes.Add(new ElementChangedEventArgs(item1.XPath, item1.Element, item1.LineNumber, item2.Element, item2.LineNumber));
                        }
                    }
                    foreach (var item in itemCollection)// marking searchable objects
                    {
                        item.isChecked = true;
                    }
                }
            }

            var addedCollection = doc2Descendants.Where(x => !x.isChecked).ToList();

            foreach (var item1 in addedCollection)
            {
                if (xPathsAdded.Any(a => item1.XPath.StartsWith(a)))
                {
                    continue;
                }

                xPathsAdded.Add(item1.XPath);

                additions.Add(new ElementAddedEventArgs(item1.XPath, item1.Element, item1.LineNumber));
            }

            stopWatch.Stop();

            Console.WriteLine("Elapsed Time {0} ms", stopWatch.ElapsedMilliseconds.ToString());

            foreach (var item in removals)
            {
                callback.ElementRemoved(item);
            }
            foreach (var item in additions)
            {
                callback.ElementAdded(item);
            }
            foreach (var item in changes)
            {
                callback.ElementChanged(item);
            }
        }
Beispiel #2
0
        public void Compare(Stream stream1, Stream stream2, IXmlCompareHandler callback)
        {
            var       loadOptions = LoadOptions.SetBaseUri | LoadOptions.SetLineInfo;
            const int leftId      = 1;
            const int rightId     = 2;

            var doc1 = XDocument.Load(stream1, loadOptions);
            var doc2 = XDocument.Load(stream2, loadOptions);

            var nsm1 = new XmlNamespaceManagerEnhanced(doc1);
            var nsm2 = new XmlNamespaceManagerEnhanced(doc2);

            var doc1Descendants = doc1.Descendants()
                                  .Where(a => a != doc1.Root)
                                  .Select(a => new { Source = leftId, Element = a });

            var doc2Descendants = doc2.Descendants()
                                  .Where(a => a != doc2.Root)
                                  .Select(a => new { Source = rightId, Element = a });

            var doc1DescendantsDiff = doc1Descendants
                                      .Where(a => !doc2Descendants.Any(a2 => ElementsAreEqual(a2.Element, a.Element)))
                                      .Select(a => Elem.Create(a.Element, a.Source))
                                      .ToList();

            var doc2DescendantsDiff = doc2Descendants
                                      .Where(a => !doc1Descendants.Any(a1 => ElementsAreEqual(a1.Element, a.Element)))
                                      .Select(a => Elem.Create(a.Element, a.Source))
                                      .ToList();

            var itemsToProcess = doc1DescendantsDiff
                                 .Concat(doc2DescendantsDiff)
                                 .OrderBy(a => a.LineNumber).ThenBy(a => a.Source)
                                 .ToList();

            var xPathsAdded   = new List <string>();
            var xPathsRemoved = new List <string>();
            var xPathsChanged = new List <string>();

            var additions = new List <ElementAddedEventArgs>();
            var changes   = new List <ElementChangedEventArgs>();
            var removals  = new List <ElementRemovedEventArgs>();

            foreach (var item in itemsToProcess)
            {
                if (xPathsAdded.Any(a => a == item.XPath) ||
                    xPathsChanged.Any(a => a == item.XPath) ||
                    xPathsRemoved.Any(a => a == item.XPath)
                    )
                {
                    continue;
                }

                //Console.WriteLine(item.XPath);

                var node1 = item.Source != leftId ? default(XElement) : item.Element;
                var node2 = item.Source != rightId ? default(XElement) : item.Element;

                // now get item from other side
                switch (item.Source)
                {
                case leftId:
                {
                    // get node2
                    var e = itemsToProcess.FirstOrDefault(a => a.Source == rightId && a.XPath == item.XPath);
                    if (e != null)
                    {
                        node2 = e.Element;
                    }
                    break;
                }

                case rightId:
                {
                    // get node1
                    var e = itemsToProcess.FirstOrDefault(a => a.Source == leftId && a.XPath == item.XPath);
                    if (e != null)
                    {
                        node1 = e.Element;
                    }
                    break;
                }

                default:
                {
                    throw new Exception("Invalid Source " + item + " for item : " + item.XPath);
                }
                }


                if (node1 != null && node2 != null)
                {
                    CompareAttributes(node1, node2, callback);

                    // if there are sub-elements, those will be handled separately
                    if (node1.HasElements || node2.HasElements)
                    {
                        continue;
                    }
                }

                if (node1 == null && node2 != null)
                {
                    //added
                    if (xPathsAdded.Any(a => item.XPath.StartsWith(a)))
                    {
                        // if the node's parent exists in the list of items,
                        // there is no need to call the callback
                        continue;
                    }

                    xPathsAdded.Add(item.XPath);

                    additions.Add(new ElementAddedEventArgs(item.XPath, node2, node2.LineNumber()));
                    continue;
                }


                if (node1 != null && node2 == null)
                {
                    //removed
                    if (xPathsRemoved.Any(a => item.XPath.StartsWith(a)))
                    {
                        // if the node's parent exists in the list of items,
                        // there is no need to call the callback
                        continue;
                    }

                    xPathsRemoved.Add(item.XPath);

                    removals.Add(new ElementRemovedEventArgs(item.XPath, node1, node1.LineNumber()));
                    continue;
                }


                if (node1 != null && node2 != null)
                {
                    //might have changed
                    //compare values

                    if (xPathsChanged.Any(a => item.XPath.StartsWith(a)))
                    {
                        // if the node's parent exists in the list of items,
                        // there is no need to call the callback
                        continue;
                    }

                    xPathsChanged.Add(item.XPath);

                    var val1 = node1.Value;
                    var val2 = node2.Value;

                    if (string.Equals(val1, val2))
                    {
                        continue;
                    }

                    changes.Add(new ElementChangedEventArgs(item.XPath, node1, node1.LineNumber(), node2, node2.LineNumber()));
                    continue;
                }

                throw new Exception("Invalid scenario while comparing elements: " + item.XPath);
            }

            foreach (var item in removals)
            {
                callback.ElementRemoved(item);
            }
            foreach (var item in additions)
            {
                callback.ElementAdded(item);
            }
            foreach (var item in changes)
            {
                callback.ElementChanged(item);
            }
        }