Check if an XML element is equal to another XML element by ignoring empty values

I check if the two XML elements specified by the string match as follows:

private static bool XmlEquals(string s1, string s2) { return XNode.DeepEquals(XElement.Parse(s1), XElement.Parse(s2)); } 

This job, if only one of the elements has no opening and closing tags, and the other has a closed tag as follows:

 <MyElement SomeAttribute="some value" /> <MyElement SomeAttribute="some value"></MyElement> 

Is there any way to compare two XML elements in such a way that the above case is considered equal ?

+6
source share
3 answers

A simple way to solve this problem is to explicitly enter the closing brackets :

  private static bool XmlEquals(string s1, string s2) { var firstElement = XElement.Parse(s1); var secondElement = XElement.Parse(s2); IntroduceClosingBracket(firstElement); IntroduceClosingBracket(secondElement); return XNode.DeepEquals(firstElement, secondElement); } private static void IntroduceClosingBracket(XElement element) { foreach (var descendant in element.DescendantsAndSelf()) { if (descendant.IsEmpty) { descendant.SetValue(String.Empty); } } } 

A loop through all descendants can cause a performance hit.

+2
source

If XML does not have to be completely identical, as in the @defaultlocale solution, which really compares everything (even comments), you can use LINQ to compare only those things that interest you. To show the idea I made a comparison of optional attribute values.

Test data:

 var xml1 = @" <elm1 attr1='val1'> <elm2 attr2='val1'> <elm3 attr3='val1' /> </elm2> </elm1>"; var xml2 = @" <elm1 attr1='val1'> <elm2 attr2='val1'> <elm3 attr3='val1' attr='val2' /> </elm2> </elm1>"; 

Recursive comparison:

 // Just a helper. private static Tuple<XElement, XElement> Compare( string xml1, string xml2, bool compareAttributeValues) { return Compare( XElement.Parse(xml1), XElement.Parse(xml2), compareAttributeValues); } // Compares XElements recursively // and returns the two nodes that are different if any. private static Tuple<XElement, XElement> Compare( XElement xElm1, XElement xElm2, bool compareAttributeValues) { // Elements are different if they have a different number of children. if (xElm1.Elements().Count() != xElm2.Elements().Count()) { return new Tuple<XElement, XElement>(xElm1, xElm2); } // Enumerate both elements at the same time. var elements = Enumerable.Zip( xElm1.Elements(), xElm2.Elements(), (x, y) => new Tuple<XElement, XElement>(x, y)); foreach (var item elements ) { // Elements are equal if they have the same names... bool haveSameNames = xElm1.Name.LocalName == xElm2.Name.LocalName; // and the same attributes. bool haveSameAttributes = item.Item1 // Concatenate and group attributes by their name. .Attributes() .Concat(item.Item2.Attributes()) .GroupBy(x => x.Name.LocalName, (key, items) => new { Name = key, Items = items, // Attiribute value comparison can be skipped. // If enabled compare attribute values. // They are equal if the result is only one group. HaveSameValues = compareAttributeValues == false || items.GroupBy(y => y.Value).Count() == 1, Count = items.Count() }) // Each attribute group must contain two items // if they are identical (one per element). .Where(x => x.Count != 2 || x.HaveSameValues == false) .Any() == false; if (!haveSameNames || !haveSameAttributes) { return item; } else { // Return the different nodes. return Compare(item.Item1, item.Item2, compareAttributeValues); } } // No differences found. return null; } 
+1
source

You can always put strings in quotation marks and then compare them.

 s1Array = s1.Split('\"'); s2Array = s2.Split('\"'); if(s1[0] == s2[0] && s1[1] == s2[1]) return true; 

Ignoring empty values ​​is as easy as checking

 if(s1[1] == String.Empty || s1[1] == null)... 
-5
source

Source: https://habr.com/ru/post/980700/


All Articles