У меня есть 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 правильно?
Если у вас есть только байты, вы можете либо загрузить байты в поток:
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);
Почему беспокоиться, чтобы прочитать файл в качестве последовательности байтов, а затем преобразовывать его в строку, когда это файл XML? Просто оставьте рамки сделать загрузку для вас и справиться с кодировками:
var xml = XDocument.Load("test.xml");
У вас есть байт-маркет (BOM) в начале вашего XML, и соответствует ли он вашим кодировке? Если вы нарезаете свой заголовок, вы также поручите BOM, и если это неверно, то последующие разборы могут работать.
Вам может потребоваться осмотреть ваш документ на уровне байта, чтобы увидеть BOM.
Моей первой мыслью было, что при разборе XML с .NET-строковым типом кодировка является Unicode. Похоже, что парсинг XDocument довольно прощающий в этом отношении.
Проблема на самом деле связана с меткой преамбулы/байтового порядка UTF8 (BOM), которая представляет собой трехбайтовую сигнатуру , опционально присутствующую в начале потока 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);
}