XPath vs DeSerialization:哪一个在读取操作方面性能更好

时间:2008-11-10 11:59:56

标签: c# wcf performance serialization xpath

我将小型(2-10 KB)XML文档作为输入传递给WCF服务。现在我有两个选项来读取传入XML中的数据值

  1. 反序列化为强类型对象并使用对象属性访问值
  2. 使用XPath访问值
  3. 哪种方法更快?一些支持你答案的统计数据会很棒。

3 个答案:

答案 0 :(得分:8)

我会反序化它。

如果使用xpath,无论如何都要将它反序列化(或“加载”)到XmlDocument或其他东西。因此,这两种解决方案都使用时间反序列化。完成此操作后,由于解析该字符串,解析名称,执行函数等所花费的时间,xpath将变慢。此外,如果你使用xpath,你就没有类型安全。您的编译器无法为您检查xpath语法。

如果您使用XmlSerializer和类,则会获得静态类型。真的可以快速访问你的数据,如果你想用xpath查询它们,还有办法做到这一点。

另外,我想说你的代码可能更容易理解类。

唯一的缺点是xml必须始终符合相同的模式,但在您的情况下这可能不是真正的问题。

我希望你原谅没有统计数据,我认为这些论点足够强大而没有例子。如果你想要一个终极答案,试试两个并准备一个秒表。

答案 1 :(得分:4)

第三种方法是坚持使用XML,但使用您正在使用的任何XML API进行查询 - 例如LINQ to XML使代码中的查询相对简单。

您是否已将文本解析为XML文档?

您是否确信这实际上是代码中的重要性能瓶颈? (例如,如果您正在与数据库交谈,那么请不要担心这一点 - 首先让它以最简单的方式工作)

查询总是相同,还是以某种方式动态?

您是否拥有包含真实消息和查询的测试平台?如果没有,您需要一个,以便使用您的数据评估此处给出的任何答案。如果你这样做,我希望你自己尝试它是相当容易的:)

答案 2 :(得分:2)

以下是4个案例,所有时间都在刻度和放置中:

  • XmlSerializer(Slowest 4th)
  • 实施IXmlSerializable(3rd)
  • 手卷(自定义)(第1个)
  • XElement(2nd)

示例对象被读取了1000次。

你应该关心吗?对于大多数情况,请使用.net中内置的默认序列化程序。没有必要偏离,这将产生最少量的代码。这些应该是绰绰有余的,提供类型安全,并释放自己与时间做更有意义的事情。在某些情况下,如果您希望从大型XML结构中挑选某些数据元素,则XElement可能很有用,但即使这样,也应该将这些元素放入强类型DTO中。但请记住,所有方法都非常快。我个人在几毫秒内亲自序列化了一个非常广泛和深入的对象模型(超过400个clases)。对于较小和平凡的对象,它将是子ms响应时间。 XMLSerializer预热比其他的慢,但可以通过SGEN缓解或在启动时进行一些初始化。

详细信息和代码......

Xml Serializer

[Serializable]
    public class FoobarXml
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public bool IsContent { get; set; }

        [XmlElement(DataType = "date")]
        public DateTime BirthDay { get; set; }
    }

第一次:2448965

1000阅读平均值:245

<强> IXmlSerializable的

 public class FoobarIXml : IXmlSerializable
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public bool IsContent { get; set; }
        public DateTime BirthDay { get; set; }

        public XmlSchema GetSchema()
        {
            return null;
        }

        public void ReadXml(XmlReader reader)
        {
            reader.MoveToContent();
            var isEmptyElement = reader.IsEmptyElement;
            reader.ReadStartElement();
            if (!isEmptyElement)
            {
                Name = reader.ReadElementString("Name");

                int intResult;
                var success = int.TryParse(reader.ReadElementString("Age"), out intResult);
                if (success)
                {
                    Age = intResult;
                }

                bool boolResult;
                success = bool.TryParse(reader.ReadElementString("IsContent"), out boolResult);
                if (success)
                {
                    IsContent = boolResult;
                }
                DateTime dateTimeResult;
                success = DateTime.TryParseExact(reader.ReadElementString("BirthDay"), "yyyy-MM-dd", null,
                    DateTimeStyles.None, out dateTimeResult);
                if (success)
                {
                    BirthDay = dateTimeResult;
                }
                reader.ReadEndElement(); //Must Do
            }
        }

        public void WriteXml(XmlWriter writer)
        {
            writer.WriteElementString("Name", Name);
            writer.WriteElementString("Age", Age.ToString());
            writer.WriteElementString("IsContent", IsContent.ToString());
            writer.WriteElementString("BirthDay", BirthDay.ToString("yyyy-MM-dd"));
        }
    }
}

第一次:2051813

1000阅读平均值:208

手动

 public class FoobarHandRolled
    {
        public FoobarHandRolled(string name, int age, bool isContent, DateTime birthDay)
        {
            Name = name;
            Age = age;
            IsContent = isContent;
            BirthDay = birthDay;
        }

        public FoobarHandRolled(string xml)
        {
            if (string.IsNullOrWhiteSpace(xml))
            {
                return;
            }

            SetName(xml);
            SetAge(xml);
            SetIsContent(xml);
            SetBirthday(xml);
        }

        public string Name { get; set; }
        public int Age { get; set; }
        public bool IsContent { get; set; }
        public DateTime BirthDay { get; set; }

        /// <summary>
        ///     Takes this object and creates an XML representation.
        /// </summary>
        /// <returns>An XML string that represents this object.</returns>
        public override string ToString()
        {
            var builder = new StringBuilder();
            builder.Append("<FoobarHandRolled>");

            if (!string.IsNullOrWhiteSpace(Name))
            {
                builder.Append("<Name>" + Name + "</Name>");
            }

            builder.Append("<Age>" + Age + "</Age>");
            builder.Append("<IsContent>" + IsContent + "</IsContent>");
            builder.Append("<BirthDay>" + BirthDay.ToString("yyyy-MM-dd") + "</BirthDay>");
            builder.Append("</FoobarHandRolled>");

            return builder.ToString();
        }

        private void SetName(string xml)
        {
            Name = GetSubString(xml, "<Name>", "</Name>");
        }

        private void SetAge(string xml)
        {
            var ageString = GetSubString(xml, "<Age>", "</Age>");
            int result;
            var success = int.TryParse(ageString, out result);
            if (success)
            {
                Age = result;
            }
        }

        private void SetIsContent(string xml)
        {
            var isContentString = GetSubString(xml, "<IsContent>", "</IsContent>");
            bool result;
            var success = bool.TryParse(isContentString, out result);
            if (success)
            {
                IsContent = result;
            }
        }

        private void SetBirthday(string xml)
        {
            var dateString = GetSubString(xml, "<BirthDay>", "</BirthDay>");
            DateTime result;
            var success = DateTime.TryParseExact(dateString, "yyyy-MM-dd", null, DateTimeStyles.None, out result);
            if (success)
            {
                BirthDay = result;
            }
        }

        private string GetSubString(string xml, string startTag, string endTag)
        {
            var startIndex = xml.IndexOf(startTag, StringComparison.Ordinal);
            if (startIndex < 0)
            {
                return null;
            }

            startIndex = startIndex + startTag.Length;

            var endIndex = xml.IndexOf(endTag, StringComparison.Ordinal);
            if (endIndex < 0)
            {
                return null;
            }

            return xml.Substring(startIndex, endIndex - startIndex);
        }
    }

第一次:161105

1000阅读平均值:29

<强> 的XElement

        var xDoc = XElement.Parse(xml);

        var nameElement = xDoc.Element("Name");
        var ageElement = xDoc.Element("Age");
        var isContentElement = xDoc.Element("IsContent");
        var birthDayElement = xDoc.Element("BirthDay");

        string name = null;
        if (nameElement != null)
        {
            name = nameElement.Value;
        }
        var age = 0;
        if (ageElement != null)
        {
            age = int.Parse(ageElement.Value);
        }
        var isContent = false;
        if (isContentElement != null)
        {
            isContent = bool.Parse(isContentElement.Value);
        }
        var birthDay = new DateTime();
        if (birthDayElement != null)
        {
            birthDay = DateTime.ParseExact(birthDayElement.Value, "yyyy-MM-dd", CultureInfo.InvariantCulture);
        }

第一次:247024

1000阅读平均值:113