Почему С# XmlDocument.LoadXml(строка) терпит неудачу при включении заголовка XML?
Кто-нибудь может понять, почему следующий пример кода завершился с ошибкой XmlException. "Данные на корневом уровне недействительны. Строка 1, позиция 1."
var body = "<?xml version="1.0" encoding="utf-16"?><Report> ......"
XmlDocument bodyDoc = new XmlDocument();
bodyDoc.LoadXml(body);
Ответы
Ответ 1
Фон
Несмотря на то, что у вашего вопроса есть кодировка, установленная как UTF-16, у вас нет строки, которая правильно экранирована, поэтому я не был уверен, что вы действительно переставляете строку в свой вопрос.
Я столкнулся с тем же исключением:
System.Xml.XmlException: данные на root недопустим. Линия 1, положение 1.
Однако мой код выглядел так:
string xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<event>This is a Test</event>";
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xml);
Проблема
Проблема состоит в том, что строки хранятся внутри UTF-16 в .NET, однако кодировка, указанная в заголовке документа XML, может быть разной. Например:.
<?xml version="1.0" encoding="utf-8"?>
Из документации MSDN для String здесь:
Каждый символ Юникода в строке определяемый скалярным значением Unicode, также называемый кодовой точкой Unicode или порядковое (числовое) значение Юникод. Каждая кодовая точка кодируется с использованием кодировки UTF-16, и числовое значение каждого элемента кодирование представлено Charобъект.
Это означает, что когда вы передаете XmlDocument.LoadXml() свою строку с заголовком XML, она должна сказать, что кодировка UTF-16. В противном случае фактическое базовое кодирование не будет соответствовать кодировке, указанной в заголовке, и приведет к тому, что будет выведено исключение XmlException.
Решение
Решение этой проблемы состоит в том, чтобы убедиться, что кодировка, используемая во всем, что вы передаете методу Load или LoadXml, соответствует тому, что вы говорите в заголовке XML. В моем примере выше либо измените свой XML-заголовок на состояние UTF-16, либо для кодирования ввода в UTF-8 и используйте один из методов XmlDocument.Load.
Ниже приведен пример кода, демонстрирующего, как использовать MemoryStream для создания XmlDocument с использованием строки, которая определяет XML-документ с кодировкой UTF-8 (но, конечно, хранится строка UTF-16.NET).
string xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<event>This is a Test</event>";
// Encode the XML string in a UTF-8 byte array
byte[] encodedString = Encoding.UTF8.GetBytes(xml);
// Put the byte array into a stream and rewind it to the beginning
MemoryStream ms = new MemoryStream(encodedString);
ms.Flush();
ms.Position = 0;
// Build the XmlDocument from the MemorySteam of UTF-8 encoded bytes
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(ms);
Ответ 2
Простое и эффективное решение: вместо использования метода LoadXml()
используйте метод Load()
Например:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("sample.xml");
Ответ 3
Попробуйте следующее:
XmlDocument bodyDoc = new XmlDocument();
bodyDoc.XMLResolver = null;
bodyDoc.Load(body);
Ответ 4
Я понял это. Прочтите документацию MSDN, и он говорит, что следует использовать .Load вместо LoadXml при чтении из строк. Обнаружено, что это работает 100% времени. Как ни странно, использование StringReader вызывает проблемы. Я думаю, что основная причина заключается в том, что это строковая кодировка Unicode, которая может вызвать проблемы, поскольку StringReader является только UTF-8.
MemoryStream stream = new MemoryStream();
byte[] data = body.PayloadEncoding.GetBytes(body.Payload);
stream.Write(data, 0, data.Length);
stream.Seek(0, SeekOrigin.Begin);
XmlTextReader reader = new XmlTextReader(stream);
// MSDN reccomends we use Load instead of LoadXml when using in memory XML payloads
bodyDoc.Load(reader);
Ответ 5
Это сработало для меня:
var xdoc = new XmlDocument { XmlResolver = null };
xdoc.LoadXml(xmlFragment);
Ответ 6
Это действительно спасло мой день.
Я написал метод расширения на основе ответа Zach, также я расширил его, чтобы использовать кодировку в качестве параметра, позволяя использовать разные кодировки рядом с UTF-8, и я завернул MemoryStream в "использование", утверждение.
public static class XmlHelperExtentions
{
/// <summary>
/// Loads a string through .Load() instead of .LoadXml()
/// This prevents character encoding problems.
/// </summary>
/// <param name="xmlDocument"></param>
/// <param name="xmlString"></param>
public static void LoadString(this XmlDocument xmlDocument, string xmlString, Encoding encoding = null) {
if (encoding == null) {
encoding = Encoding.UTF8;
}
// Encode the XML string in a byte array
byte[] encodedString = encoding.GetBytes(xmlString);
// Put the byte array into a stream and rewind it to the beginning
using (var ms = new MemoryStream(encodedString)) {
ms.Flush();
ms.Position = 0;
// Build the XmlDocument from the MemorySteam of UTF-8 encoded bytes
xmlDocument.Load(ms);
}
}
}
Ответ 7
У меня была такая же проблема при переключении с абсолютного на относительный путь для моего xml файла.
Следующее решает как загрузку, так и использование относительных проблем с источником.
Использование XmlDataProvider, которое определено в xaml (должно быть возможно и в коде):
<Window.Resources>
<XmlDataProvider
x:Name="myDP"
x:Key="MyData"
Source=""
XPath="/RootElement/Element"
IsAsynchronous="False"
IsInitialLoadEnabled="True"
debug:PresentationTraceSources.TraceLevel="High" /> </Window.Resources>
Поставщик данных автоматически загружает документ после установки источника. Здесь код:
m_DataProvider = this.FindResource("MyData") as XmlDataProvider;
FileInfo file = new FileInfo("MyXmlFile.xml");
m_DataProvider.Document = new XmlDocument();
m_DataProvider.Source = new Uri(file.FullName);
Ответ 8
Простая строка:
bodyDoc.LoadXml(new MemoryStream(Encoding.Unicode.GetBytes(body)));