Синтаксический анализ XML-строки в XML-документе завершится неудачно, если строка начинается с раздела <? Xml ...?> - PullRequest
27 голосов
/ 21 января 2010

У меня есть XML-файл, начинающийся так:

<?xml version="1.0" encoding="utf-8"?>
<Report xmlns:rd="http://schemas.microsoft.com/SQLServer/reporting/reportdesigner" xmlns="http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition">
  <DataSources>

Когда я запускаю следующий код:

byte[] fileContent = //gets bytes
            string stringContent = Encoding.UTF8.GetString(fileContent);
            XDocument xml = XDocument.Parse(stringContent);

Я получаю следующее исключение XmlException:

Данные на корневом уровне недействительны. Строка 1, позиция 1.

Вырезание версии и узла кодирования устраняет проблему. Зачем? Как правильно обработать этот xml?

Ответы [ 5 ]

24 голосов
/ 21 января 2010

Моей первой мыслью было то, что при синтаксическом анализе XML из строкового типа .NET используется кодировка Unicode. Похоже, что разбор XDocument довольно прост в этом отношении.

Проблема фактически связана с меткой порядка преамбул / байтов UTF8, которая представляет собой трехбайтовую сигнатуру , которая необязательно присутствует в начале потока UTF-8. Эти три байта являются подсказкой относительно кодировки, используемой в потоке.

Вы можете определить преамбулу кодировки, вызвав метод GetPreamble для экземпляра класса System.Text.Encoding. Например:

// returns { 0xEF, 0xBB, 0xBF }
byte[] preamble = Encoding.UTF8.GetPreamble();

Преамбула должна корректно обрабатываться XmlTextReader, поэтому просто загрузите ваш XDocument из XmlTextReader:

XDocument xml;
using (var xmlStream = new MemoryStream(fileContent))
using (var xmlReader = new XmlTextReader(xmlStream))
{
    xml = XDocument.Load(xmlReader);
}
17 голосов
/ 22 января 2010

Если у вас есть только байты, вы можете загрузить байты в поток:

XmlDocument oXML;

using (MemoryStream oStream = new MemoryStream(oBytes))
{
  oXML = new XmlDocument();
  oXML.Load(oStream);
}

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

string sXml;
XmlDocument oXml;

sXml = Encoding.UTF8.GetString(oBytes);
oXml = new XmlDocument();
oXml.LoadXml(sXml);

Я показал мой пример как совместимый с .NET 2.0, если вы используете .NET 3.5, вы можете использовать XDocument вместо XmlDocument.

Загрузка байтов в поток:

XDocument oXML;

using (MemoryStream oStream = new MemoryStream(oBytes))
using (XmlTextReader oReader = new XmlTextReader(oStream))
{
  oXML = XDocument.Load(oReader);
}

Преобразование байтов в строку:

string sXml;
XDocument oXml;

sXml = Encoding.UTF8.GetString(oBytes);
oXml = XDocument.Parse(sXml);
8 голосов
/ 21 января 2010

Зачем беспокоиться о том, чтобы прочитать файл как последовательность байтов, а затем преобразовать его в строку, пока это файл XML? Просто оставьте рамки делать загрузку для вас и справиться с кодировками:

var xml = XDocument.Load("test.xml");
6 голосов
/ 21 января 2010

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

Возможно, вам потребуется проверить документ на уровне байтов, чтобы увидеть спецификацию.

2 голосов
/ 09 июля 2013

Попробуйте это:

int startIndex = xmlString.IndexOf('<');
if (startIndex > 0)
{
    xmlString = xmlString.Remove(0, startIndex);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...