检查 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元素,使上述情况被视为相等?
解决此特定问题的直接方法是显式引入右括号:
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)...