Почему происходит сбой C # XmlDocument.LoadXml (string), если включен заголовок XML? - PullRequest
60 голосов
/ 22 ноября 2008

Кто-нибудь имеет представление, почему следующий пример кода завершается с ошибкой XmlException "Данные на корневом уровне недопустимы. Строка 1, позиция 1."

var body = "<?xml version="1.0" encoding="utf-16"?><Report> ......"
XmlDocument bodyDoc = new XmlDocument();            
bodyDoc.LoadXml(body);

Ответы [ 9 ]

116 голосов
/ 23 июня 2009

Фон

Хотя для вашего вопроса задана кодировка UTF-16, строка не экранирована должным образом, поэтому я не был уверен, действительно ли вы точно перенесли строку в свой вопрос.

Я столкнулся с тем же исключением:

System.Xml.XmlException: данные на Корневой уровень недействителен. Строка 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, может отличаться. E.g.:

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

Из документации MSDN для String здесь :

Каждый символ Unicode в строке определяется скалярным значением Unicode, также называется кодовой точкой Unicode или порядковое (числовое) значение Юникод символ Каждая кодовая точка кодируется с использованием кодировки UTF-16, и числовое значение каждого элемента кодировка представлена ​​символом объект.

Это означает, что когда вы передаете XmlDocument.LoadXml () вашу строку с заголовком XML, она должна указывать кодировку UTF-16. В противном случае фактическая базовая кодировка не будет соответствовать кодировке, указанной в заголовке, и приведет к возникновению исключения XmlException.

Решение

Решение этой проблемы состоит в том, чтобы убедиться, что кодировка, используемая во всех передаваемых вами методах Load или LoadXml, совпадает с той, что вы говорите в заголовке XML. В приведенном выше примере измените заголовок XML на состояние UTF-16 или закодируйте ввод в UTF-8 и используйте один из XmlDocument.Load методов .

.

Ниже приведен пример кода, демонстрирующий, как использовать MemoryStream для создания XmlDocument с использованием строки, которая определяет XML-документ с кодировкой UTF-8 (но, конечно, хранится строка .NET UTF-16).

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);
28 голосов
/ 27 октября 2011

Простое и эффективное решение: вместо метода LoadXml() используйте метод Load()

Например:

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("sample.xml");
7 голосов
/ 18 сентября 2009

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

XmlDocument bodyDoc = new XmlDocument();
bodyDoc.XMLResolver = null;
bodyDoc.Load(body);
6 голосов
/ 22 ноября 2008

Я понял это. Прочитайте документацию 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);
2 голосов
/ 17 мая 2013

Это действительно спасло мой день.

Я написал метод расширения, основанный на ответе Зака, а также расширил его, чтобы использовать кодирование в качестве параметра, позволяющего использовать различные кодировки, помимо UTF-8, и обернул MemoryStream в «using» заявление.

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);
        }
    }
}
2 голосов
/ 01 декабря 2010

Это сработало для меня:

var xdoc = new XmlDocument { XmlResolver = null };  
xdoc.LoadXml(xmlFragment);
1 голос
/ 05 ноября 2013

У меня была такая же проблема при переключении с абсолютного на относительный путь для моего 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);
0 голосов
/ 14 июня 2018

У меня была та же проблема, потому что файл XML, который я загружал, был закодирован с использованием UTF-8-BOM (метка порядка байтов UTF-8).

Переключил кодировку на UTF-8 в Notepad ++ и смог загрузить файл XML в коде.

0 голосов
/ 06 июня 2017

Простая строка:

bodyDoc.LoadXml(new MemoryStream(Encoding.Unicode.GetBytes(body)));

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...