XPath против DeSerialization: какой из них лучше по производительности для операций чтения - PullRequest
8 голосов
/ 10 ноября 2008

Я передаю небольшие (2-10 КБ) XML-документы в качестве входных данных для службы WCF. Теперь у меня есть два варианта для чтения значений данных из входящего XML

  1. Десериализация в строго типизированный объект и использование свойств объекта для доступа к значениям
  2. использовать XPath для доступа к значениям

какой подход быстрее? немного статистики в поддержку вашего ответа было бы здорово.

Ответы [ 3 ]

8 голосов
/ 21 ноября 2008

Я бы десериализовал это.

Если вы используете xpath, вы будете десериализовать (или «загрузить») его в XmlDocument или что-то еще. Таким образом, оба решения используют десериализацию времени. После того, как это будет сделано, xpath будет работать медленнее из-за времени, затрачиваемого на разбор этой строки, разрешение имен, выполнение функций и так далее. Кроме того, если вы используете xpath, вы не получаете безопасность типов. Ваш компилятор не может проверить синтаксис xpath за вас.

Если вы используете XmlSerializer и классы, вы получаете статическую типизацию. Очень быстрый доступ к вашим данным, и если вы хотите запросить их с помощью xpath, есть еще способы сделать это.

Кроме того, я хотел бы сказать, что ваш код, вероятно, будет легче понять с помощью классов.

Единственным недостатком является то, что xml должен постоянно соответствовать одной и той же схеме, но в вашем случае это может не быть реальной проблемой.

Я надеюсь, что вы простите отсутствие статистики, я думаю, что аргументы достаточно веские без примеров. Если вы хотите получить окончательный ответ, попробуйте оба варианта и держите секундомер наготове.

4 голосов
/ 10 ноября 2008

Существует третий вариант придерживаться XML, но запрашивать с любым XML API, который вы используете - например, LINQ to XML делает запросы относительно простыми в коде.

Вы уже проанализировали текст в XML-документе?

Вы уверены, что это на самом деле существенное узкое место в производительности вашего кода? (например, если вы затем говорите с базой данных, не беспокойтесь об этом, для начала - просто сначала запустите ее для работы)

Запросы всегда одинаковы или они в некотором роде динамические?

У вас есть испытательный стенд с реалистичными сообщениями и запросами? Если нет, вам нужен один для оценки любых ответов, приведенных здесь, с вашими данными. Если вы это сделаете, я ожидаю, что это будет довольно легко попробовать сами:)

2 голосов
/ 06 июня 2016

Вот 4 случая, все время в тиках и размещении:

  • XmlSerializer (самый медленный 4-й)
  • Реализация IXmlSerializable (3rd)
  • Ручной прокат (Custom) (1-й)
  • XElement (2nd)

Объект-образец прочитан 1000 раз.

Вас это волнует? В большинстве случаев используйте сериализаторы по умолчанию, встроенные в .net. Нет необходимости отклоняться, и это приведет к минимальному количеству кода. Это должно быть более чем достаточно, обеспечить безопасность типов и освободить себя, чтобы делать больше значимых вещей со своим временем. В некоторых случаях XElement может быть полезен, если вы хотите выделить некоторые элементы данных из большой XML-структуры, но даже тогда следует поместить эти элементы в строго типизированный DTO. Но имейте в виду, все методы очень быстрые. Я лично сериализовал чрезвычайно широкую и глубокую объектную модель (более 400 предложений) всего за несколько миллисекунд. Для более мелких и тривиальных объектов это будет время отклика менее 1 мс. Разогрев 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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...