10

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

  1. 反序列化为强类型对象并使用对象属性访问值
  2. 使用 XPath 访问值

哪种方法更快?一些支持您的答案的统计数据会很棒。

4

3 回答 3

9

我会反序列化它。

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

如果您使用 XmlSerializer 和类,您将获得静态类型。真正快速地访问您的数据,如果您想使用 xpath 查询它们,仍然有办法做到这一点。

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

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

我希望你原谅没有统计数据,我认为没有例子的论点就足够了。如果您想要最终答案,请尝试两者并准备好秒表。

于 2008-11-20T23:16:15.540 回答
4

还有第三种坚持使用 XML 的选项,但是使用您正在使用的任何 XML API 进行查询——例如 LINQ to XML 使得查询在代码中相对简单。

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

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

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

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

于 2008-11-10T12:04:25.657 回答
2

这里有 4 个案例,所有时间都在刻度和位置:

  • XmlSerializer(最慢的第 4 位)
  • 实现 IXmlSerializable(第 3 次)
  • 手卷(定制)(第 1 次)
  • XElement(第二名)

样本对象被读取 1000 次。

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

详细信息和代码...

Xml 序列化程序

[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

元素

        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

于 2016-06-06T19:27:28.760 回答