.net – 比较XElement对象的最佳方法
发布时间:2020-12-16 07:56:29 所属栏目:百科 来源:网络整理
导读:在单元测试中,我将XElement对象与我预期的对象进行比较.我使用的方法是在XElement对象上调用.ToString(),并将其与硬编码的字符串值进行比较.这种方法原来是非常不舒服,因为我总是要注意字符串中的格式. 我检查了XElement.DeepEquals()方法,但由于任何原因,它
|
在单元测试中,我将XElement对象与我预期的对象进行比较.我使用的方法是在XElement对象上调用.ToString(),并将其与硬编码的字符串值进行比较.这种方法原来是非常不舒服,因为我总是要注意字符串中的格式.
我检查了XElement.DeepEquals()方法,但由于任何原因,它没有帮助. 有人有想法我应该使用什么最好的方法?
我发现
this excellent article有用.它包含一个代码示例,实现了XNode.DeepEquals的替代方法,在比较之前规范了XML树,这使得非语义内容无关紧要.
为了说明,对于这些语义上等效的文档,XNode.DeepEquals的实现返回false: XElement root1 = XElement.Parse("<Root a='1' b='2'><Child>1</Child></Root>");
XElement root2 = XElement.Parse("<Root b='2' a='1'><Child>1</Child></Root>");
然而,从文章中使用DeepEqualsWithNormalization的实现,您将得到值为true,因为属性的顺序不被认为是重要的.这个实现包括在下面. using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Schema;
public static class MyExtensions
{
public static string ToStringAlignAttributes(this XDocument document)
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.OmitXmlDeclaration = true;
settings.NewLineOnAttributes = true;
StringBuilder stringBuilder = new StringBuilder();
using (XmlWriter xmlWriter = XmlWriter.Create(stringBuilder,settings))
document.WriteTo(xmlWriter);
return stringBuilder.ToString();
}
}
class Program
{
private static class Xsi
{
public static XNamespace xsi = “http://www.w3.org/2001/XMLSchema-instance”;
public static XName schemaLocation = xsi + “schemaLocation”;
public static XName noNamespaceSchemaLocation = xsi + “noNamespaceSchemaLocation”;
}
public static XDocument Normalize(XDocument source,XmlSchemaSet schema)
{
bool havePSVI = false;
// validate,throw errors,add PSVI information
if (schema != null)
{
source.Validate(schema,null,true);
havePSVI = true;
}
return new XDocument(
source.Declaration,source.Nodes().Select(n =>
{
// Remove comments,processing instructions,and text nodes that are
// children of XDocument. Only white space text nodes are allowed as
// children of a document,so we can remove all text nodes.
if (n is XComment || n is XProcessingInstruction || n is XText)
return null;
XElement e = n as XElement;
if (e != null)
return NormalizeElement(e,havePSVI);
return n;
}
)
);
}
public static bool DeepEqualsWithNormalization(XDocument doc1,XDocument doc2,XmlSchemaSet schemaSet)
{
XDocument d1 = Normalize(doc1,schemaSet);
XDocument d2 = Normalize(doc2,schemaSet);
return XNode.DeepEquals(d1,d2);
}
private static IEnumerable<XAttribute> NormalizeAttributes(XElement element,bool havePSVI)
{
return element.Attributes()
.Where(a => !a.IsNamespaceDeclaration &&
a.Name != Xsi.schemaLocation &&
a.Name != Xsi.noNamespaceSchemaLocation)
.OrderBy(a => a.Name.NamespaceName)
.ThenBy(a => a.Name.LocalName)
.Select(
a =>
{
if (havePSVI)
{
var dt = a.GetSchemaInfo().SchemaType.TypeCode;
switch (dt)
{
case XmlTypeCode.Boolean:
return new XAttribute(a.Name,(bool)a);
case XmlTypeCode.DateTime:
return new XAttribute(a.Name,(DateTime)a);
case XmlTypeCode.Decimal:
return new XAttribute(a.Name,(decimal)a);
case XmlTypeCode.Double:
return new XAttribute(a.Name,(double)a);
case XmlTypeCode.Float:
return new XAttribute(a.Name,(float)a);
case XmlTypeCode.HexBinary:
case XmlTypeCode.Language:
return new XAttribute(a.Name,((string)a).ToLower());
}
}
return a;
}
);
}
private static XNode NormalizeNode(XNode node,bool havePSVI)
{
// trim comments and processing instructions from normalized tree
if (node is XComment || node is XProcessingInstruction)
return null;
XElement e = node as XElement;
if (e != null)
return NormalizeElement(e,havePSVI);
// Only thing left is XCData and XText,so clone them
return node;
}
private static XElement NormalizeElement(XElement element,bool havePSVI)
{
if (havePSVI)
{
var dt = element.GetSchemaInfo();
switch (dt.SchemaType.TypeCode)
{
case XmlTypeCode.Boolean:
return new XElement(element.Name,NormalizeAttributes(element,havePSVI),(bool)element);
case XmlTypeCode.DateTime:
return new XElement(element.Name,(DateTime)element);
case XmlTypeCode.Decimal:
return new XElement(element.Name,(decimal)element);
case XmlTypeCode.Double:
return new XElement(element.Name,(double)element);
case XmlTypeCode.Float:
return new XElement(element.Name,(float)element);
case XmlTypeCode.HexBinary:
case XmlTypeCode.Language:
return new XElement(element.Name,((string)element).ToLower());
default:
return new XElement(element.Name,element.Nodes().Select(n => NormalizeNode(n,havePSVI))
);
}
}
else
{
return new XElement(element.Name,havePSVI))
);
}
}
}
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
