10

小さな (2 ~ 10 KB) XML ドキュメントを入力として WCF サービスに渡しています。受信 XML からデータ値を読み取るための 2 つのオプションがあります。

  1. 厳密に型指定されたオブジェクトに逆シリアル化し、オブジェクト プロパティを使用して値にアクセスする
  2. XPath を使用して値にアクセスする

どちらのアプローチが速いですか?あなたの答えを裏付けるいくつかの統計は素晴らしいでしょう。

4

3 に答える 3

9

私はそれを逆シリアル化します。

xpath を使用する場合は、XmlDocument などに逆シリアル化 (または「ロード」) します。したがって、両方のソリューションで時間の逆シリアル化が使用されます。これが完了すると、その文字列の解析、名前の解決、関数の実行などに時間がかかるため、xpath は遅くなります。また、xpath を使用すると、タイプ セーフが得られません。コンパイラは xpath 構文をチェックできません。

XmlSerializer とクラスを使用すると、静的型付けが得られます。データへのアクセスは非常に高速で、xpath を使用してクエリを実行したい場合は、それを行う方法がまだあります。

また、クラスを使用すると、コードが理解しやすくなると思います。

唯一の欠点は、xml が常に同じスキーマに準拠する必要があることですが、それは実際の問題ではないかもしれません。

統計がないことをご容赦ください。例がなくても、議論は十分に強力だと思います。究極の答えが必要な場合は、両方を試して、ストップウォッチを用意してください。

于 2008-11-20T23:16:15.540 に答える
4

XML に固執する 3 番目のオプションがありますが、使用している XML API を使用してクエリを実行します。たとえば、LINQ to XML を使用すると、クエリをコードで比較的簡単に作成できます。

テキストを既に XML ドキュメントに解析しましたか?

これが実際にコードの重大なパフォーマンスのボトルネックであると確信していますか? (たとえば、データベースと話している場合は、最初からこれについて心配する必要はありません。最初に最も簡単な方法で動作させるだけです)

クエリは常に同じですか、それとも何らかの形で動的ですか?

現実的なメッセージとクエリを備えたテスト装置はありますか? そうでない場合は、ここで与えられた回答をデータで評価するために必要です。もしそうなら、自分で試すのはかなり簡単だと思います:)

于 2008-11-10T12:04:25.657 に答える
2

ここに 4 つのケースがあり、すべてティックと配置で表示されます。

  • XmlSerializer (最も遅い 4 番目)
  • IXmlSerializable の実装 (3 番目)
  • 手巻き(カスタム)(1st)
  • XElement (2 番目)

サンプル オブジェクトは 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

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

于 2016-06-06T19:27:28.760 に答える