Подтвердить что ты не робот

Проверить хорошо сформированный XML без try/catch?

Кто-нибудь знает, как я могу проверить, содержит ли строка хорошо сформированный XML, не используя что-то вроде XmlDocument.LoadXml() в блоке try/catch? У меня есть данные, которые могут быть или не быть XML, и я хочу, чтобы код, который распознает, что вход может быть не XML, не полагаясь на try/catch, как по скорости, так и по общему принципу, что не исключительные обстоятельства не должны поднимать исключения. В настоящее время у меня есть код, который делает это:

private bool IsValidXML(string value)
    {
        try
        {
            // Check we actually have a value
            if (string.IsNullOrEmpty(value) == false)
            {
                // Try to load the value into a document
                XmlDocument xmlDoc = new XmlDocument();

                xmlDoc.LoadXml(value);

                // If we managed with no exception then this is valid XML!
                return true;
            }
            else
            {
                // A blank value is not valid xml
                return false;
            }
        }
        catch (System.Xml.XmlException)
        {
            return false;
        }
    }

Но это похоже на то, что не должно требовать try/catch. Исключение вызывает адский ад во время отладки, потому что каждый раз, когда я проверяю строку, отладчик будет ломаться здесь, "помогая" мне с моей надоедливой проблемой.

4b9b3361

Ответ 1

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

Для этого перейдите в раздел "Отладка/Исключения..." / "Исключения общего времени выполнения языка" и найдите "Исключить System.Xml.XmlException", затем убедитесь, что "Пользователь не обработан" отмечен (не выбрасывается).

Ответ 2

Стив,

У нас была сторонняя сторона, которая случайно иногда отправляла нам JSON вместо XML. Вот что я реализовал:

public static bool IsValidXml(string xmlString)
{
    Regex tagsWithData = new Regex("<\\w+>[^<]+</\\w+>");

    //Light checking
    if (string.IsNullOrEmpty(xmlString) || tagsWithData.IsMatch(xmlString) == false)
    {
        return false;
    }

    try
    {
        XmlDocument xmlDocument = new XmlDocument();
        xmlDocument.LoadXml(xmlString);
        return true;
    }
    catch (Exception e1)
    {
        return false;
    }
}

[TestMethod()]
public void TestValidXml()
{
    string xml = "<result>true</result>";
    Assert.IsTrue(Utility.IsValidXml(xml));
}

[TestMethod()]
public void TestIsNotValidXml()
{
    string json = "{ \"result\": \"true\" }";
    Assert.IsFalse(Utility.IsValidXml(json));
}

Ответ 3

Это разумный способ сделать это, за исключением того, что IsNullOrEmpty избыточен (LoadXml может понять, что это нормально). Если вы сохраните IsNullOrEmpty, выполните, если (! String.IsNullOrEmpty(значение)).

В принципе, однако, ваш отладчик является проблемой, а не кодом.

Ответ 4

Добавьте атрибут [System.Diagnostics.DebuggerStepThrough] к методу IsValidXml. Это исключает исключение XmlException из улавливания отладчиком, что означает, что вы можете включить улавливание исключений с первым изменением, и этот конкретный метод не будет отлажен.

Ответ 5

Осторожно, используя XmlDocument, чтобы можно было загрузить элемент вдоль линий <0>some text</0>, используя XmlDocument doc = (XmlDocument)JsonConvert.DeserializeXmlNode(object) без исключения.

Числовые имена элементов недействительны xml, и в моем случае ошибка не возникала до тех пор, пока я не попытался записать xmlDoc.innerText в тип данных сервера Sql для xml.

Это, как я проверяю сейчас, и исключение получает XmlDocument tempDoc = XmlDocument)JsonConvert.DeserializeXmlNode(formData.ToString(), "data"); doc.LoadXml(tempDoc.InnerXml);

Ответ 6

Класс XmlTextReader является реализация XmlReader и обеспечивает быстрый, эффективный синтаксический анализатор. Это применяет правила, которые должны быть хорошо сформирован. Это не валидация или не проверяющий парсер поскольку он не имеет DTD или схемы Информация. Он может читать текст в блоков или считывать символы из поток.

И пример из другой статьи MSDN, к которой я добавил код для чтения все содержимое XML-потока.

string str = "<ROOT>AQID</ROOT>";
XmlTextReader r = new XmlTextReader(new StringReader(str));
try
{
  while (r.Read())
  {
  }
}
finally
{
  r.Close();
}

источник: http://bytes.com/topic/c-sharp/answers/261090-check-wellformedness-xml

Ответ 7

Я не согласен с тем, что проблема - отладчик. В целом, в исключительных случаях исключения следует избегать. Это означает, что если кто-то ищет метод типа IsWellFormed(), который возвращает true/false на основании того, является ли ввод корректно сформированным XML или нет, исключения не должны быть выбрасываться внутри этой реализации независимо от того, пойманы они или обработаны или нет,

Исключения являются дорогостоящими, и они не должны встречаться при нормальном успешном выполнении. Примером может быть запись метода, который проверяет существование файла и использования File.Open и перехватывает исключение в случае, если файл не существует. Это было бы плохой реализацией. Вместо этого следует использовать File.Exists() (и, надеюсь, реализация этого не просто ставит try/catch вокруг некоторого метода, который генерирует исключение, если файл не существует, я уверен, что это не так).

Ответ 8

Только мои 2 цента - есть разные вопросы об этом, и большинство людей согласны с фактом "мусор в мусоре". Я не согласен с этим, но лично я нашел следующее быстрое и грязное решение, особенно для случаев, когда вы имеете дело с xml-данными от сторонних сторон, которые просто не общаются с вами легко. Это не позволяет использовать try/catch, но он использует его с меньшей детализацией, поэтому в случаях, когда количество недействительных символов xml не так велико, это помогает... Я использовал XmlTextReader и его метод ReadChars() для каждого родительского элемента, который является одной из команд которые не выполняют хорошо сформированные проверки, например ReadInner/OuterXml. Таким образом, это комбинация Read() и ReadChars(), когда Read() stubmbles на родительском node. Конечно, это работает, потому что я могу предположить, что базовая структура XML в порядке, но содержимое (значения) определенных узлов может содержать специальные символы, которые не были заменены на &..; эквивалент... (я нашел статью об этом где-то, но не могу найти ссылку источника на данный момент)

Ответ 9

Я использую следующие функции для документов/фрагментов

<Runtime.CompilerServices.Extension()>
Public Function IsValidXMLFragment(ByVal xmlFragment As String, Optional Strict As Boolean = False) As Boolean
    IsValidXMLFragment = True

    Dim NameTable As New Xml.NameTable

    Dim XmlNamespaceManager As New Xml.XmlNamespaceManager(NameTable)
    XmlNamespaceManager.AddNamespace("xsd", "http://www.w3.org/2001/XMLSchema")
    XmlNamespaceManager.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance")

    Dim XmlParserContext As New Xml.XmlParserContext(Nothing, XmlNamespaceManager, Nothing, Xml.XmlSpace.None)

    Dim XmlReaderSettings As New Xml.XmlReaderSettings
    XmlReaderSettings.ConformanceLevel = Xml.ConformanceLevel.Fragment
    XmlReaderSettings.ValidationType = Xml.ValidationType.Schema
    If Strict Then
        XmlReaderSettings.ValidationFlags = (XmlReaderSettings.ValidationFlags Or XmlSchemaValidationFlags.ProcessInlineSchema)
        XmlReaderSettings.ValidationFlags = (XmlReaderSettings.ValidationFlags Or XmlSchemaValidationFlags.ReportValidationWarnings)
    Else
        XmlReaderSettings.ValidationFlags = XmlSchemaValidationFlags.None
        XmlReaderSettings.ValidationFlags = (XmlReaderSettings.ValidationFlags Or XmlSchemaValidationFlags.AllowXmlAttributes)
    End If

    AddHandler XmlReaderSettings.ValidationEventHandler, Sub() IsValidXMLFragment = False
    AddHandler XmlReaderSettings.ValidationEventHandler, AddressOf XMLValidationCallBack

    Dim XmlReader As Xml.XmlReader = Xml.XmlReader.Create(New IO.StringReader(xmlFragment), XmlReaderSettings, XmlParserContext)
    While XmlReader.Read
        'Read entire XML
    End While
End Function

Public Function IsValidXMLDocument(ByVal Path As String, Optional Strict As Boolean = False) As Boolean
    IsValidXMLDocument = IO.File.Exists(Path)
    If Not IsValidXMLDocument Then Exit Function

    Dim XmlReaderSettings As New Xml.XmlReaderSettings
    XmlReaderSettings.ConformanceLevel = Xml.ConformanceLevel.Document
    XmlReaderSettings.ValidationType = Xml.ValidationType.Schema
    If Strict Then
        XmlReaderSettings.ValidationFlags = (XmlReaderSettings.ValidationFlags Or XmlSchemaValidationFlags.ProcessInlineSchema)
        XmlReaderSettings.ValidationFlags = (XmlReaderSettings.ValidationFlags Or XmlSchemaValidationFlags.ReportValidationWarnings)
    Else
        XmlReaderSettings.ValidationFlags = XmlSchemaValidationFlags.None
        XmlReaderSettings.ValidationFlags = (XmlReaderSettings.ValidationFlags Or XmlSchemaValidationFlags.AllowXmlAttributes)
    End If

    AddHandler XmlReaderSettings.ValidationEventHandler, Sub() IsValidXMLDocument = False
    AddHandler XmlReaderSettings.ValidationEventHandler, AddressOf XMLValidationCallBack

    Dim FileStream As New IO.FileStream(Path, IO.FileMode.Open)
    Dim XmlReader As Xml.XmlReader = Xml.XmlReader.Create(FileStream, XmlReaderSettings)
    While XmlReader.Read
        'Read entire XML
    End While
End Function

Ответ 10

Я использую эту функцию для проверки строк/фрагментов

<Runtime.CompilerServices.Extension()>
Public Function IsValidXMLFragment(ByVal xmlFragment As String, Optional Strict As Boolean = False) As Boolean
    IsValidXMLFragment = True

    Dim NameTable As New Xml.NameTable

    Dim XmlNamespaceManager As New Xml.XmlNamespaceManager(NameTable)
    XmlNamespaceManager.AddNamespace("xsd", "http://www.w3.org/2001/XMLSchema")
    XmlNamespaceManager.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance")

    Dim XmlParserContext As New Xml.XmlParserContext(Nothing, XmlNamespaceManager, Nothing, Xml.XmlSpace.None)

    Dim XmlReaderSettings As New Xml.XmlReaderSettings
    XmlReaderSettings.ConformanceLevel = Xml.ConformanceLevel.Fragment
    XmlReaderSettings.ValidationType = Xml.ValidationType.Schema
    If Strict Then
        XmlReaderSettings.ValidationFlags = (XmlReaderSettings.ValidationFlags Or XmlSchemaValidationFlags.ProcessInlineSchema)
        XmlReaderSettings.ValidationFlags = (XmlReaderSettings.ValidationFlags Or XmlSchemaValidationFlags.ReportValidationWarnings)
    Else
        XmlReaderSettings.ValidationFlags = XmlSchemaValidationFlags.None
        XmlReaderSettings.ValidationFlags = (XmlReaderSettings.ValidationFlags Or XmlSchemaValidationFlags.AllowXmlAttributes)
    End If

    AddHandler XmlReaderSettings.ValidationEventHandler, Sub() IsValidXMLFragment = False
    AddHandler XmlReaderSettings.ValidationEventHandler, AddressOf XMLValidationCallBack

    Dim XmlReader As Xml.XmlReader = Xml.XmlReader.Create(New IO.StringReader(xmlFragment), XmlReaderSettings, XmlParserContext)
    While XmlReader.Read
        'Read entire XML
    End While
End Function

Я использую эту функцию для проверки файлов:

Public Function IsValidXMLDocument(ByVal Path As String, Optional Strict As Boolean = False) As Boolean
    IsValidXMLDocument = IO.File.Exists(Path)
    If Not IsValidXMLDocument Then Exit Function

    Dim XmlReaderSettings As New Xml.XmlReaderSettings
    XmlReaderSettings.ConformanceLevel = Xml.ConformanceLevel.Document
    XmlReaderSettings.ValidationType = Xml.ValidationType.Schema
    If Strict Then
        XmlReaderSettings.ValidationFlags = (XmlReaderSettings.ValidationFlags Or XmlSchemaValidationFlags.ProcessInlineSchema)
        XmlReaderSettings.ValidationFlags = (XmlReaderSettings.ValidationFlags Or XmlSchemaValidationFlags.ReportValidationWarnings)
    Else
        XmlReaderSettings.ValidationFlags = XmlSchemaValidationFlags.None
        XmlReaderSettings.ValidationFlags = (XmlReaderSettings.ValidationFlags Or XmlSchemaValidationFlags.AllowXmlAttributes)
    End If
    XmlReaderSettings.CloseInput = True

    AddHandler XmlReaderSettings.ValidationEventHandler, Sub() IsValidXMLDocument = False
    AddHandler XmlReaderSettings.ValidationEventHandler, AddressOf XMLValidationCallBack

    Using FileStream As New IO.FileStream(Path, IO.FileMode.Open)
        Using XmlReader As Xml.XmlReader = Xml.XmlReader.Create(FileStream, XmlReaderSettings)
            While XmlReader.Read
                'Read entire XML
            End While
        End Using
    End Using
End Function

Ответ 11

Мои два цента. Это было довольно просто и следует некоторым общим соглашениям, так как это касается разбора...

public bool TryParse(string s, ref XmlDocument result)
{
    try {
        result = new XmlDocument();
        result.LoadXml(s);
        return true;
    } catch (XmlException ex) {
        return false;
    }
}