Тестирование того, является ли что-то синтаксическое XML в С#

Кто-нибудь знает быстрый способ проверить, что строка обрабатывается как XML в С#? Предпочтительно, что-то быстрый, низкий ресурс, который возвращает логическое значение независимо от того, будет ли он разбираться.

Я работаю над приложением базы данных, которое касается ошибок, которые иногда хранятся как XML, а иногда и нет. Следовательно, я бы хотел просто проверить строку, которую я быстро извлекаю из базы данных (содержащуюся в DataTable)... и не должен прибегать к какому-либо запросу try/catch {} или другим kludges... если только это единственный способ сделать это.

Ответ 1

Похоже, что вы иногда возвращаете XML, а иногда вы получаете "простой" (не XML) текст.

В этом случае вы можете просто проверить, что текст начинается с <:

if (!string.IsNullOrEmpty(str) && str.TrimStart().StartsWith("<"))
    var doc = XDocument.Parse(str);

Поскольку "простые" сообщения, кажется, не начинаются с < это может быть разумным. Единственное, что вам нужно решить, это что делать в крайнем случае, если у вас есть не-XML текст, который начинается с <?

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

if (!string.IsNullOrEmpty(str) && str.TrimStart().StartsWith("<"))
{
    try
    {
        var doc = XDocument.Parse(str);
        return //???
    }   
    catch(Exception ex)
        return str;
}
else
{
    return str;   
}

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

Ответ 2

Вы можете попытаться проанализировать строку в XDocument. Если это не удается проанализировать, вы знаете, что это неверно.

string xml = "";
XDocument document = XDocument.Parse(xml);

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

public static bool IsValidXml(this string xml)
{
    try
    {
        XDocument.Parse(xml);
        return true;
    }
    catch
    {
        return false;
    }
}

Тогда ваш код просто выглядит как if (mystring.IsValidXml()) {

Ответ 3

Единственный способ узнать, действительно ли что-то на самом деле разобрать, - это... попытаться разобрать его.

Документ XMl должен (но не обязательно) иметь объявление XML во главе файла, следуя спецификации (если присутствует). Он должен выглядеть примерно так:

<?xml version="1.0" encoding="UTF-8" ?>

Хотя атрибут кодирования, я полагаю, является необязательным (по умолчанию используется UTF-8. Он также может иметь атрибут standalone, значение которого yes или no. Если это присутствует, это довольно хороший индикатор что документ должен быть действительным XML.

Riffing on @GaryWalker отличный ответ, что-то вроде этого примерно так же хорошо, как и получается, я думаю (хотя для настройки может потребоваться некоторая настройка, op resolver возможно). Просто для ударов я сгенерировал случайный XML файл размером 300 МБ, используя XMark xmlgen (http://www.xml-benchmark.org/): проверка его с помощью приведенного ниже кода занимает 1,7 – 1,8 секунды истекшего времени на моем настольном компьютере.

public static bool IsMinimallyValidXml( Stream stream )
{
  XmlReaderSettings settings = new XmlReaderSettings
    {
      CheckCharacters              = true                          ,
      ConformanceLevel             = ConformanceLevel.Document     ,
      DtdProcessing                = DtdProcessing.Ignore          ,
      IgnoreComments               = true                          ,
      IgnoreProcessingInstructions = true                          ,
      IgnoreWhitespace             = true                          ,
      ValidationFlags              = XmlSchemaValidationFlags.None ,
      ValidationType               = ValidationType.None           ,
    } ;
  bool isValid ;

  using ( XmlReader xmlReader = XmlReader.Create( stream , settings ) )
  {
    try
    {
      while ( xmlReader.Read() )
      {
        ; // This space intentionally left blank
      }
      isValid = true ;
    }
    catch (XmlException)
    {
      isValid = false ;
    }
  }
  return isValid ;
}

static void Main( string[] args )
{
  string text = "<foo>This &SomeEntity; is about as simple as it gets.</foo>" ;
  Stream stream = new MemoryStream( Encoding.UTF8.GetBytes(text) ) ;
  bool isValid = IsMinimallyValidXml( stream ) ;
  return ;
}

Ответ 4

Существует несколько способов определить, является ли XML действительным. Я в основном делаю два шага.

Проверьте, начинается ли он с требуемого тега XML (что-то типа)

bool result = xmlToParse.BeginsWith("<?xml");

затем убедитесь, что есть равные < и > (что-то типа)

result = xmlToParse.Count(c => c == '<') == xmlToParse.Count(c => c == '>');

помимо базовой проверки, он становится чем-то, что процесс, который на самом деле знаком с XML, должен выполняться (NOT regex), чтобы гарантировать его синтаксический анализ.