代码之家  ›  专栏  ›  技术社区  ›  usman shaheen

xpath与反序列化:哪一个在读操作中性能更好

  •  8
  • usman shaheen  · 技术社区  · 16 年前

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

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

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

    3 回复  |  直到 9 年前
        1
  •  8
  •   Guge    16 年前

    我会反序列化它。

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

    如果使用XmlSerializer和类,则会得到静态类型。对数据的快速访问,如果您想用xpath查询它们,仍然有方法做到这一点。

    另外,我想说的是,您的代码在类中可能更容易理解。

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

    我希望你能原谅统计数据的缺失,我认为没有实例的论证就足够有力了。如果你想要一个最终的答案,试着两者都做,并准备好秒表。

        2
  •  4
  •   Jon Skeet    16 年前

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

    您已经将文本解析为XML文档了吗?

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

    查询总是相同的,还是在某种程度上是动态的?

    你有一个包含真实信息和查询的测试平台吗?如果没有,您需要一个来评估这里给出的任何答案 你的 数据。如果你这样做了,我希望你自己也能很容易地尝试一下。)

        3
  •  2
  •   Jon Raynor    9 年前

    以下是4个案例,所有时间都在滴答声和放置中:

    • XML序列化程序(最慢的第4个)
    • 实现IXML可序列化(第三个)
    • 手工轧制(定制)(1)
    • XFLUE(第二)

    样本对象被读取1000次。

    你应该关心吗?对于大多数情况,使用内置于.NET中的默认序列化程序。没有必要偏离,这将产生最少的代码量。这些应该是足够的,提供类型安全和自由自己做更有意义的事情与你的时间。在某些情况下,如果希望从大型XML结构中挑选某些数据元素,Xelement可能很有用,但即使这样,也应该将这些元素放入强类型DTO中。但要记住,所有的方法都很快。我个人在几毫秒内就序列化了一个非常广泛和深入的对象模型(超过400个分支)。对于较小和琐碎的对象,它将是次MS响应时间。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

    IXML可序列化

     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

    X元素

            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