检查 XML 元素是否等于另一个 XML 元素,忽略空值

本文关键字:XML 元素 空值 是否 检查 另一个 | 更新日期: 2023-09-27 18:36:40

我正在检查字符串给出的两个XML元素是否与此方法相等:

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

除非其中一个元素具有开始和结束标记,而另一个元素具有如下所示的闭合标记,否则此操作有效:

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

我是否可以以某种方式比较两个XML元素,使上述情况被视为相等

检查 XML 元素是否等于另一个 XML 元素,忽略空值

解决此特定问题的直接方法是显式引入右括号:

 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);
           }
      }
 }

但是,遍历所有后代可能会导致性能下降。

如果XML不必像@defaultlocale的解决方案那样完全相同,该解决方案真正比较了所有内容(甚至是注释),则可以使用LINQ仅比较您感兴趣的内容。为了表明这个想法,我将属性值的比较设置为可选。

测试数据:

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>";

递归比较:

// 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;
}

当有一个空标签时,使用XNode.DeepEquals的问题,比较 XML 文档中的所有 XML 元素的最佳方法(即使 XML 结束标记不同,这也应该有效)

    public bool CompareXml()
    {
            var doc = @"
            <ContactPersons>
                <ContactPersonRole>General</ContactPersonRole>
                <Person>
                  <Name>Aravind Kumar Eriventy</Name>
                  <Email/>
                  <Mobile>9052534488</Mobile>
                </Person>
              </ContactPersons>";
            var doc1 = @"
            <ContactPersons>
                <ContactPersonRole>General</ContactPersonRole>
                <Person>
                  <Name>Aravind Kumar Eriventy</Name>
                  <Email></Email>
                  <Mobile>9052534488</Mobile>
                </Person>
              </ContactPersons>";
        return XmlDocCompare(XDocument.Parse(doc), XDocument.Parse(doc1));
    }
    private static bool XmlDocCompare(XDocument doc,XDocument doc1)
    {
        IntroduceClosingBracket(doc.Root);
        IntroduceClosingBracket(doc1.Root);
        return XNode.DeepEquals(doc1, doc);
    }
    private static void IntroduceClosingBracket(XElement element)
    {
        foreach (var descendant in element.DescendantsAndSelf())
        {
            if (descendant.IsEmpty)
            {
                descendant.SetValue(String.Empty);
            }
        }
    }

您始终可以在引号处拆分字符串,然后进行比较。

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

忽略空值就像检查一样简单

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