Производительность метода расширения .NET IsValidXml

У меня есть устаревшее приложение, которое я унаследовал, которое передает много XML в виде строк.

Мне часто нужна возможность проверить, будет ли строка допустимым XML. Каков самый быстрый и наименее затратный способ проверить, является ли строка допустимой XML в .NET?

Я работаю в .NET 3.5 и, скорее всего, буду использовать это как метод расширения (вне строки) в этом одном проекте в рамках решения.

ОБНОВЛЕНИЕ:
Под "действительным" в моем случае я подразумеваю правильно сформированный XML. Мне не нужно проверять ресурсы или схему.


person BuddyJoe    schedule 08.04.2010    source источник
comment
Что в вашем случае справедливо? Вы просто имеете в виду правильно сформированный или ожидаете, что он будет соответствовать DTD/схеме? Означает ли это, что вам нужно иметь возможность разрешать ссылочные ресурсы?   -  person Adam Robinson    schedule 08.04.2010
comment
Хорошая точка зрения. Я изменю свой вопрос.   -  person BuddyJoe    schedule 08.04.2010
comment
Интересно, должен ли я вызывать свой метод IsProperXml? или IsWellFormedXml?   -  person BuddyJoe    schedule 08.04.2010
comment
На этом уровне кажется, что IsXml сработает (ИМХО).   -  person Adam Robinson    schedule 08.04.2010
comment
Эти термины имеют особое значение: строка является правильной, если она соответствует правилам синтаксиса XML, т. е. если это XML-документ. XML-документ является действительным, если он соответствует DTD или схеме. Все допустимые XML-документы имеют правильный формат.   -  person Robert Rossney    schedule 09.04.2010


Ответы (3)


Невозможно проверить правильность формата строки XML без ее синтаксического анализа. И быстрый тест показывает, что самый быстрый способ проанализировать строку, чтобы убедиться, что она действительна (фактически самый быстрый способ проанализировать конкретную строку, которую я использую в качестве теста) с помощью XmlReader:

    static void Main(string[] args)
    {
        const int iterations = 20000;
        const string xml = @"<foo><bar><baz a='b' c='d'/><foo><bar><baz a='b' c='d'/></bar><bar/></foo><foo><bar><baz a='b' c='d'/></bar><bar/></foo><foo><bar><baz a='b' c='d'/></bar><bar/></foo><foo><bar><baz a='b' c='d'/></bar><bar/></foo><foo><bar><baz a='b' c='d'/></bar><bar/></foo><foo><bar><baz a='b' c='d'/></bar><bar/></foo><foo><bar><baz a='b' c='d'/></bar><bar/></foo><foo><bar><baz a='b' c='d'/></bar><bar/></foo><foo><bar><baz a='b' c='d'/></bar><bar/></foo></bar><bar/></foo>";

        Stopwatch st = new Stopwatch();

        st.Start();
        for (int i=0; i<iterations; i++)
        {
            using (StringReader sr = new StringReader(xml))
            using (XmlReader xr = XmlReader.Create(sr))
            {
                while (xr.Read())
                {
                }
            }
        }
        st.Stop();
        Console.WriteLine(String.Format("XmlReader: {0} ms.", st.ElapsedMilliseconds));

        st.Reset();
        st.Start();
        for (int i=0; i<iterations; i++)
        {
            XElement.Parse(xml);
        }
        st.Stop();
        Console.WriteLine(String.Format("XElement: {0} ms.", st.ElapsedMilliseconds));

        st.Reset();
        st.Start();
        for (int i = 0; i < iterations; i++)
        {
            XmlDocument d= new XmlDocument();
            d.LoadXml(xml);
        }
        st.Stop();
        Console.WriteLine(String.Format("XmlDocument: {0} ms.", st.ElapsedMilliseconds));

        st.Reset();
        st.Start();
        for (int i = 0; i < iterations; i++)
        {
            using (StringReader sr = new StringReader(xml))
            {
                XPathDocument d = new XPathDocument(new StringReader(xml));                    
            }
        }
        st.Stop();
        Console.WriteLine(String.Format("XPathDocument: {0} ms.", st.ElapsedMilliseconds));

        Console.ReadKey();
    }

На моей машине XmlReader работает почти в два раза быстрее любой из альтернатив. Это имеет смысл. Хотя я не использовал Reflector для проверки, я был бы очень удивлен, если бы XmlDocument, XDocument и XPathDocument не использовали XmlReader под капотом.

person Robert Rossney    schedule 09.04.2010

Я не знаю встроенного средства в .NET для проверки сформированности (?) XML без его разбора. Учитывая это, что-то вроде этого должно работать:

public static class XmlUtilities
{
    public static bool IsXml(this string data)
    {
        if (string.IsNullOrEmpty(data)) return false;

        try
        {
            System.Xml.XmlDocument doc = new System.Xml.XmlDocument();

            doc.LoadXml(data);

            return true;            
        }
        catch
        {
            return false;
        }
    }
}
person Adam Robinson    schedule 08.04.2010
comment
@ Стивен, пожалуйста, не редактируйте ответы таким образом, чтобы это коренным образом изменило их работу. Перехват всех исключений был преднамеренным и уместным. Хотя он мог бы быть более конкретным и перехватывать только XmlException, изменить его на использование DebuggerStepThrough совсем не то же самое. - person Adam Robinson; 15.04.2010

Согласен с Адамом и версией XElement:

public static class XmlUtilities
{

    public static bool IsXml(this string data)
    {
        if (string.IsNullOrEmpty(data)) return false;

        try
        {
            var doc = XElement.Parse(data)

            return true;            
        }
        catch (XmlException)
        {
            return false;
        }
    }
}
person Stéphane    schedule 08.04.2010
comment
зачем кому-то редактировать ответ на вопрос, на который уже был дан ответ, изменяя значение кода... размещение комментария могло бы быть более дружелюбным, на мой взгляд! - person Stéphane; 15.04.2010