Это неэффективный способ разбора XML? - PullRequest
2 голосов
/ 25 октября 2010

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

В любом случае, вот что я делаю:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Net;

namespace LinqTestingGrounds
{
    class Program
    {
        static void Main(string[] args)
        {
            WebClient webClient = new WebClient();
            webClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(webClient_DownloadStringCompleted);
            webClient.DownloadStringAsync(new Uri("http://www.dreamincode.net/forums/xml.php?showuser=335389"));
            Console.ReadLine();
        }

        static void webClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                return;
            }

            XDocument xml = XDocument.Parse(e.Result);

            User user = new User();
            user.ID = xml.Element("ipb").Element("profile").Element("id").Value;
            user.Name = xml.Element("ipb").Element("profile").Element("name").Value;
            user.Rating = xml.Element("ipb").Element("profile").Element("rating").Value;
            user.Photo = xml.Element("ipb").Element("profile").Element("photo").Value;
            user.Reputation = xml.Element("ipb").Element("profile").Element("reputation").Value;
            user.Group = xml.Element("ipb").Element("profile").Element("group").Element("span").Value;
            user.Posts = xml.Element("ipb").Element("profile").Element("posts").Value;
            user.PostsPerDay = xml.Element("ipb").Element("profile").Element("postsperday").Value;
            user.JoinDate = xml.Element("ipb").Element("profile").Element("joined").Value;
            user.ProfileViews = xml.Element("ipb").Element("profile").Element("views").Value;
            user.LastActive = xml.Element("ipb").Element("profile").Element("lastactive").Value;
            user.Location = xml.Element("ipb").Element("profile").Element("location").Value;
            user.Title = xml.Element("ipb").Element("profile").Element("title").Value;
            user.Age = xml.Element("ipb").Element("profile").Element("age").Value;
            user.Birthday= xml.Element("ipb").Element("profile").Element("birthday").Value;
            user.Gender = xml.Element("ipb").Element("profile").Element("gender").Element("gender").Element("value").Value;

            Console.WriteLine(user.ID);
            Console.WriteLine(user.Name);
            Console.WriteLine(user.Rating);
            Console.WriteLine(user.Photo);
            Console.WriteLine(user.Reputation);
            Console.WriteLine(user.Group);
            Console.WriteLine(user.Posts);
            Console.WriteLine(user.PostsPerDay);
            Console.WriteLine(user.JoinDate);
            Console.WriteLine(user.ProfileViews);
            Console.WriteLine(user.LastActive);
            Console.WriteLine(user.Location);
            Console.WriteLine(user.Title);
            Console.WriteLine(user.Age);
            Console.WriteLine(user.Birthday);
            Console.WriteLine(user.Gender);

            //Console.WriteLine(xml);            
        }
    }
}

Это Good Enough ™ или есть более быстрый способ разобрать то, что мне нужно?

пс. Я делаю основную часть операций в событии DownloadStringCompleted, не следует ли мне делать это? Впервые использую этот метод. Спасибо!

Ответы [ 4 ]

3 голосов
/ 25 октября 2010

Не знаю об эффективности, но для удобства чтения используйте переменную profile вместо того, чтобы пересматривать все заново:

 User user = new User();
 var profile = xml.Element("ipb").Element("profile");
 user.ID = profile.Element("id").Value;
2 голосов
/ 25 октября 2010

Я считаю, что сериализация в формате xml - это путь для решения проблемы такого типа. Пока ваши свойства соответствуют элементам xml, это будет тривиально. В противном случае вам просто нужно отобразить их, используя классы атрибутов XmlElement и XmlAttribute. Вот некоторый простой код для общей десериализации xml в класс:

public T Deserialise(string someXml)
    {   
        XmlSerializer reader = new XmlSerializer(typeof (T));
        StringReader stringReader = new StringReader(someXml);
        XmlTextReader xmlReader = new XmlTextReader(stringReader);
        return (T) reader.Deserialize(xmlReader);
    }
1 голос
/ 25 октября 2010

I дополнение к ответу Одеда: Другой способ улучшить читабельность - использовать XPathSelectElement метод расширения.

Итак, ваш код будет выглядеть так:

user.ID = xml.XPathSelectElement("ipb/profile/id").Value;
0 голосов
/ 25 октября 2010

Нет, это не анализирует XML снова и снова;только один раз, когда вы вызываете

XDocument.Parse(e.Result);

Вызовы после этого просто обращаются к древовидной структуре в объекте xml.

«Разбор» означает анализ неструктурированной текстовой строки (такой как происходит изфайл) и создание структур данных (таких как дерево) из него.Ваши вызовы ... .Element("foo") не разбираются, а получают доступ к частям структуры данных, которая была создана с помощью вызова XDocument.Parse().

Если вам интересно, повторяет ли ваш код некоторые шаги с избыточностью и может ли быть оптимизирован,тогда да, вы избыточно пересекаете ipb/profile.Это не синтаксический анализ, но вызовы Element ("foo") должны выполнить некоторую работу, сравнивая строковые аргументы с именами дочерних элементов.Предложение @ Oded исправляет это по соображениям читабельности, но также способствует эффективности.

...