.net – 比较XElement对象的最佳方法

前端之家收集整理的这篇文章主要介绍了.net – 比较XElement对象的最佳方法前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
在单元测试中,我将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))
            );
        }
    }
}

猜你在找的XML相关文章