10 Stimmen

XPath vs. DeSerialization: Welche Methode ist die bessere für Lesevorgänge?

Ich übergebe kleine (2-10 KB) XML-Dokumente als Input zu einem WCF-Dienst. jetzt habe ich zwei Optionen, um Datenwerte aus eingehenden XML zu lesen

  1. Deserialisierung in ein stark typisiertes Objekt und Verwendung von Objekteigenschaften für den Zugriff auf Werte
  2. XPath für den Zugriff auf Werte verwenden

Welcher Ansatz ist schneller? Ein paar Statistiken zur Untermauerung Ihrer Antwort wären toll.

9voto

Guge Punkte 4587

Ich würde es deserialisieren.

Wenn Sie xpath verwenden, werden Sie deserialisieren (oder "laden") es zu XmlDocument oder etwas sowieso. Also beide Lösungen verwenden Zeit deserialisieren. Nachdem dies geschehen ist, wird xpath langsamer sein, weil die Zeit für das Parsen der Zeichenkette, das Auflösen von Namen, das Ausführen von Funktionen und so weiter benötigt wird. Wenn man sich für xpath entscheidet, erhält man auch keine Typsicherheit. Ihr Compiler kann die xpath-Syntax nicht für Sie überprüfen.

Wenn Sie XmlSerializer und Klassen verwenden, erhalten Sie statische Typisierung. Wirklich schnellen Zugriff auf Ihre Daten, und wenn Sie sie mit xpath abfragen wollen, gibt es immer noch Möglichkeiten, das zu tun.

Außerdem möchte ich anmerken, dass Ihr Code mit Klassen wahrscheinlich leichter zu verstehen wäre.

Der einzige Nachteil ist, dass die XML-Datei immer demselben Schema entsprechen muss, aber das dürfte in Ihrem Fall kein wirkliches Problem darstellen.

Ich hoffe, Sie verzeihen das Fehlen von Statistiken, denn ich denke, die Argumente sind auch ohne Beispiele stark genug. Wenn Sie eine endgültige Antwort wollen, versuchen Sie beides und halten Sie eine Stoppuhr bereit.

4voto

Jon Skeet Punkte 1325502

Eine dritte Möglichkeit besteht darin, bei XML zu bleiben, aber Abfragen mit der von Ihnen verwendeten XML-API durchzuführen - z. B. LINQ to XML macht Abfragen relativ einfach im Code.

Haben Sie den Text bereits in ein XML-Dokument geparst?

Sind Sie davon überzeugt, dass dies tatsächlich einen erheblichen Leistungsengpass in Ihrem Code darstellt? (Wenn Sie z. B. mit einer Datenbank kommunizieren, brauchen Sie sich darüber zunächst keine Gedanken zu machen - bringen Sie es erst einmal auf die einfachste Weise zum Laufen)

Sind die Abfragen immer gleich oder sind sie in irgendeiner Weise dynamisch?

Verfügen Sie über einen Prüfstand mit realistischen Meldungen und Abfragen? Wenn nicht, brauchen Sie einen, um die hier gegebenen Antworten mit Ihr Daten. Wenn Sie dies tun, dürfte es relativ einfach sein, es selbst zu versuchen :)

2voto

Jon Raynor Punkte 3686

Hier sind 4 Fälle, alle Zeiten in Ticks und Platzierung:

  • XmlSerializer (Langsamster 4.)
  • Implementierung von IXmlSerializable (3.)
  • Handgerollt (Custom) (1.)
  • XElement (2.)

Das Beispielobjekt wurde 1000 Mal gelesen.

Sollten Sie sich darum kümmern? In den meisten Fällen sollten Sie die Standard-Serializer verwenden, die in .net integriert sind. Es besteht keine Notwendigkeit, davon abzuweichen, und das wird die minimale Menge an Code erzeugen. Diese sollten mehr als ausreichend sein, bieten Typsicherheit und geben Ihnen die Freiheit, Ihre Zeit für sinnvollere Dinge zu nutzen. In einigen Fällen kann XElement nützlich sein, wenn man bestimmte Datenelemente aus einer großen XML-Struktur herausgreifen möchte, aber selbst dann sollte man diese Elemente in ein stark typisiertes DTO packen. Aber bedenken Sie, dass alle Methoden sehr schnell sind. Ich persönlich habe ein extrem breites und tiefes Objektmodell (weit über 400 Clases) in nur wenigen Millisekunden serialisiert. Bei kleineren und trivialen Objekten liegen die Antwortzeiten unter ms. Die Aufwärmphase von XMLSerializer ist langsamer als die der anderen, aber das kann man mit SGEN oder einer Initialisierung beim Starten abmildern.

Details und Code...

Xml-Serialisierer

[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; }
    }

Erstes Mal: 2448965

1000 Gelesener Durchschnitt: 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"));
        }
    }
}

Erstes Mal: 2051813

1000 Gelesener Durchschnitt: 208

Handgerollt

 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);
        }
    }

Erstes Mal: 161105

1000 Gelesener Durchschnitt: 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);
        }

Erstes Mal: 247024

1000 Lesen Durchschnitt: 113

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X