Example #1
0
        private XElement DoChangeElement(XElement target, bool throwOnError, XDiffOptions options)
        {
            var e = Find(target, BasisElement, options);

            if (null == e)
            {
                if (throwOnError)
                {
                    throw new Exception("cannot find target for " + BasisElement);
                }
                return(target);
            }
            if (NewValue.Contains("<") && NewValue.Contains(">"))
            {
                e.Nodes().ToArray().Remove();
                var x = XElement.Parse("<a>" + NewValue + "</a>");
                foreach (var n in x.Nodes())
                {
                    e.Add(n);
                }
            }
            else
            {
                e.Value = NewValue;
            }
            return(target);
        }
Example #2
0
        private XElement DoCreateAttribute(XElement target, bool throwOnError, XDiffOptions options)
        {
            var e = Find(target, BasisElement, options);

            if (null == e)
            {
                if (throwOnError)
                {
                    throw new Exception("cannot find target for " + BasisElement);
                }
                return(target);
            }
            if (null == NewestAttribute)
            {
                foreach (var a in NewestElement.Attributes())
                {
                    e.SetAttributeValue(a.Name, a.Value);
                }
            }
            else
            {
                e.SetAttributeValue(NewestAttribute.Name.LocalName, NewestAttribute.Value);
            }
            return(target);
        }
Example #3
0
 public XDiffKey(XDiffOptions opts, XElement e)
 {
     _options = opts;
     Name     = e.Name.LocalName;
     Id       = e.Attr("id");
     Code     = e.Attr("code");
 }
Example #4
0
        /// <summary>
        /// Применяет разницу к исходному элементу
        /// </summary>
        public XElement Apply(XElement target, bool throwOnError = true, XDiffOptions options = null)
        {
            options = options ?? new XDiffOptions();
            switch (Action)
            {
            case XDiffAction.CreateElement:
                return(DoCreateElement(target, throwOnError, options));

            case XDiffAction.DeleteElement:
                return(DoDeleteElement(target, throwOnError, options));

            case XDiffAction.ChangeElement:
                return(DoChangeElement(target, throwOnError, options));

            case XDiffAction.RenameElement:
                return(DoRenameElement(target, throwOnError, options));

            case XDiffAction.CreateAttribute:
                return(DoCreateAttribute(target, throwOnError, options));

            case XDiffAction.DeleteAttribute:
                return(DoDeleteAttribute(target, throwOnError, options));

            case XDiffAction.ChangeAttribute:
                return(DoChangeAttribute(target, throwOnError, options));

            case XDiffAction.ChangeHierarchyPosition:
                return(DoChangeHierarchyPosition(target, throwOnError, options));
            }
            return(target);
        }
Example #5
0
        private XElement DoCreateElement(XElement target, bool throwOnError, XDiffOptions options)
        {
            var t      = target;
            var parent = NewestElement.Attribute("__parent");

            if (null != parent)
            {
                t = FindByParent(target, new ParentCondition(parent.Value));
            }
            if (null == t)
            {
                throw new Exception("cannot find target parent elment " + parent);
            }
            if (options.IsHierarchy)              //мы должны порождать элементы без дочек во избежание дублирования, дочки накатятся сами
            {
                var header = new XElement(NewestElement);
                header.Elements().Remove();
                var p = header.Attribute("__parent");
                if (null != p)
                {
                    p.Remove();
                }
                t.Add(header);
            }
            else
            {
                t.Add(new XElement(NewestElement));
            }

            return(target);
        }
Example #6
0
        XElement Find(XElement target, string finder, XDiffOptions options)
        {
            var finds    = finder.Split('-');
            var name     = "";
            var attrname = "";
            var val      = "";

            if (finds.Length == 3)
            {
                name     = finds[0];
                attrname = finds[1];
                val      = finds[2];
            }
            else
            {
                attrname = finds[0];
                val      = finds[1];
            }
            Func <XElement, bool> ismatch = e => {
                if (name != "" && name != e.Name.LocalName)
                {
                    return(false);
                }
                var a = e.Attribute(attrname);
                if (null == a)
                {
                    return(false);
                }
                return(a.Value == val);
            };

            XElement[] result;
            if (options.IsHierarchy)
            {
                result = target.Descendants().Where(ismatch).ToArray();
            }
            else
            {
                result = target.Elements().Where(ismatch).ToArray();
            }
            if (0 == result.Length)
            {
                return(null);
            }
            if (1 == result.Length)
            {
                return(result[0]);
            }
            throw new Exception("double match");
        }
Example #7
0
        private XElement DoRenameElement(XElement target, bool throwOnError, XDiffOptions options)
        {
            var e = Find(target, BasisElement, options);

            if (null == e)
            {
                if (throwOnError)
                {
                    throw new Exception("cannot find target for " + BasisElement);
                }
                return(target);
            }
            e.Name = NewValue;
            return(target);
        }
Example #8
0
        private XElement DoDeleteElement(XElement target, bool throwOnError, XDiffOptions options)
        {
            var e = Find(target, BasisElement, options);

            if (null == e)
            {
                if (throwOnError)
                {
                    throw new Exception("cannot find target for " + BasisElement);
                }
                return(target);
            }
            e.Remove();
            return(target);
        }
Example #9
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <param name="__options"></param>
        /// <returns></returns>
        public static bool IsJoined(XElement a, XElement b, XDiffOptions __options)
        {
            //тут не на кодах, id используется как первичный ключ
            var aid    = __options.ChangeIds? null : a.Attribute("id");
            var haid   = aid != null;
            var bid    = __options.ChangeIds ? null : b.Attribute("id");
            var hbid   = bid != null;
            var acode  = a.Attribute("code");
            var hacode = acode != null;
            var bcode  = b.Attribute("code");
            var hbcode = bcode != null;

            if (!haid && !hacode)
            {
                return(false);                              //no identity on a
            }
            if (!hbid && !hbcode)
            {
                return(false);                              //no idenityt on a
            }
            var testvala = "";
            var testvalb = "";

            if (haid && hbid)              // both on ids
            {
                testvala = aid.Value;
                testvalb = bid.Value;
            }
            else if (hacode && hbcode)
            {
                testvala = acode.Value;
                testvalb = bcode.Value;
            }
            else
            {
                return(false);                //some incompability checks
            }
            if (testvala != testvalb)
            {
                return(false);
            }
            if (__options.IsNameIndepended)
            {
                return(true);
            }
            return(a.Name.LocalName == b.Name.LocalName);
        }
Example #10
0
        private XElement DoDeleteAttribute(XElement target, bool throwOnError, XDiffOptions options)
        {
            var e = Find(target, BasisElement, options);

            if (null == e)
            {
                if (throwOnError)
                {
                    throw new Exception("cannot find target for " + BasisElement);
                }
                return(target);
            }
            var ex = e.Attribute(BasisAttribute.Name.LocalName);

            if (null != ex)
            {
                ex.Remove();
            }
            return(target);
        }
Example #11
0
 XElement Find(XElement target, XElement search, XDiffOptions options)
 {
     XElement[] result;
     if (options.IsHierarchy)
     {
         result = target.Descendants().Where(_ => XDiffExtensions.IsJoined(_, search, options)).ToArray();
     }
     else
     {
         result = target.Elements().Where(_ => XDiffExtensions.IsJoined(_, search, options)).ToArray();
     }
     if (0 == result.Length)
     {
         return(null);
     }
     if (1 == result.Length)
     {
         return(result[0]);
     }
     throw new Exception("double match");
 }
Example #12
0
		private static string GetResult(XElement b, XElement n, XDiffOptions opts = null){
			var result = new XDiffGenerator(opts).GetDiff(b, n).LogToString().Replace("\"", "'").Trim();
			Console.WriteLine(result);
			return result;
		}
Example #13
0
		public void CanAppplyPatchHierarchcallyWithNameChanges()
		{
			var b = XElement.Parse("<a><z code='2' name='y'/><z id='3' code='4'><x id='5' name='x'/></z></a>");
			var n = XElement.Parse("<a><u code='2' name='y'><y id='5' name='x'/></u><z id='3' code='4'></z></a>");
			var opts = new XDiffOptions{IsHierarchy = true, IsNameIndepended = true};
			GetResult(b, n, opts);
			Assert.True(new XDiffGenerator(opts).IsDiff(b, n));
			var result = new XDiffGenerator(opts).GetDiff(b, n).Apply(b,opts);
			Console.WriteLine(result.ToString());
			Assert.False(new XDiffGenerator(opts).IsDiff(b, n));
		}
Example #14
0
		public void CanMergeNonSeparateDeleteAsChangesAttributes()
		{
			var b = XElement.Parse("<a><z id='1' name='2' a='3' b='4' c='5' x='aaa6'/></a>");
			var n = XElement.Parse("<a><z id='1' name='2' a='3' b='3' /></a>");
			var opts = new XDiffOptions { MergeAttributeChanges = true, TreatDeleteAttributesAsChanges = true };
			var diff = new XDiffGenerator(opts).GetDiff(b, n).ToArray();
			var log = diff.LogToString();
			Console.WriteLine(log);
			Assert.AreEqual(1, diff.Length);
			Assert.AreEqual(@"ChangeAttribute n0
	BasisElement name=z id=1
	NewestElement : (<update b=""3"" c=""0"" x="""" />)
".LfOnly().Trim(), log.LfOnly().Trim());

			diff.Apply(b, opts);
			Console.WriteLine(b);
			Assert.AreEqual(@"<a>
  <z id=""1"" name=""2"" a=""3"" b=""3"" c=""0"" x="""" />
</a>".Trim().LfOnly(),b.ToString().Trim().LfOnly());
		}
Example #15
0
		public void CanMergeNonSeparateNewAndUpdatedAttributes()
		{
			var b = XElement.Parse("<a><z id='1' name='2' a='3' b='4' c='5'/></a>");
			var n = XElement.Parse("<a><z id='1' name='2' a='6' b='4' c='7' d='8' e='9'/></a>");
			var opts = new XDiffOptions { MergeAttributeChanges = true,TreatNewAttributesAsChanges = true};
			var diff = new XDiffGenerator(opts).GetDiff(b, n).ToArray();
			var log = diff.LogToString();
			Console.WriteLine(log);
			Assert.AreEqual(1, diff.Length);
			Assert.AreEqual(@"ChangeAttribute n0
	BasisElement name=z id=1
	NewestElement : (<update a=""6"" c=""7"" d=""8"" e=""9"" />)
", log);

			diff.Apply(b, opts);
			Assert.False(new XDiffGenerator().IsDiff(b, n));
		}
Example #16
0
		public void CanPreventActions()
		{
			var b = XElement.Parse("<a><z id='1' code='2'/><z id='3' code='4'/></a>");
			var n = XElement.Parse("<a><z id='3' code='2'/><z id='1' code='4'/><z id='5'/></a>");
			var opts = new XDiffOptions();
			opts.ErrorActions = opts.ErrorActions | XDiffAction.CreateElement;
			Assert.Throws<Exception>(()=> GetResult(b, n, opts));
		}
Example #17
0
		public void CanFilterActions()
		{
			var b = XElement.Parse("<a><z id='1' code='2'/><z id='3' code='4'/></a>");
			var n = XElement.Parse("<a><z id='3' set-code='2'/><z id='1' set-code='4'/><z id='5'/></a>");

			var result = GetResult(b, n);
			Assert.AreEqual(@"CreateElement n0
	NewestElement : (<z id='5' />)
ChangeAttribute n1
	BasisElement name=z id=1
	NewestAttribute code :4
ChangeAttribute n2
	BasisElement name=z id=3
	NewestAttribute code :2".Length, result.Length);
			Console.WriteLine();
			var opts = new XDiffOptions();
			opts.IncludeActions = opts.IncludeActions & ~XDiffAction.CreateElement;
			result = GetResult(b, n, opts);
			Assert.AreEqual(@"ChangeAttribute n0
	BasisElement name=z id=1
	NewestAttribute code :4
ChangeAttribute n1
	BasisElement name=z id=3
	NewestAttribute code :2".Length, result.Length);
			Console.WriteLine();
			opts = new XDiffOptions();
			opts.IncludeActions = opts.IncludeActions & ~XDiffAction.ChangeAttribute;
			result = GetResult(b, n, opts);
			Assert.AreEqual(@"CreateElement n0
	NewestElement : (<z id='5' />)".Length, result.Length);
		}
Example #18
0
        private XElement DoChangeHierarchyPosition(XElement target, bool throwOnError, XDiffOptions options)
        {
            var e = Find(target, BasisElement, options);

            if (null == e)
            {
                if (throwOnError)
                {
                    throw new Exception("cannot find target for " + BasisElement);
                }
                return(target);
            }
            var __parent = e.Attribute("__parent");
            var pval     = NewValue;

            __parent.Remove();
            e.Remove();
            if (string.IsNullOrWhiteSpace(pval))
            {
                target.Add(e);
            }
            else
            {
                var newtarg = Find(target, pval, options);
                if (null == newtarg)
                {
                    if (throwOnError)
                    {
                        throw new Exception("cannot find target for " + pval);
                    }
                    return(target);
                }
                newtarg.Add(e);
            }
            return(target);
        }
Example #19
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="diffs"></param>
        /// <param name="target"></param>
        /// <param name="options"></param>
        public static XElement Apply(this IEnumerable <XDiffItem> diffs, XElement target, XDiffOptions options = null)
        {
            options = options ?? new XDiffOptions();
            IDictionary <string, string> movereplaces = new Dictionary <string, string>();
            var orderedDiffs = diffs.
                               OrderBy(_ => _.Action)
                               .ThenByDescending(_ => null == _.NewestElement ? 0 : _.NewestElement.Descendants().Count())
                               .ToArray();

            foreach (var diff in orderedDiffs)
            {
                if (diff.CanChangeHierarchyTarget)
                {
                    FillDictionary(movereplaces, diff);
                }
                else if (diff.CanChangeHierarchyTarget)
                {
                    while (movereplaces.ContainsKey(diff.NewValue))
                    {
                        diff.NewValue = movereplaces[diff.NewValue];
                    }
                }
                diff.Apply(target, true, options);
            }
            return(target);
        }
Example #20
0
 /// <summary>
 /// </summary>
 public XDiffGenerator(XDiffOptions options = null)
 {
     _options = options ?? new XDiffOptions();
 }