Почему C# XmlDocument.LoadXml (строка) не работает при включении заголовка XML?

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

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

Дэн прав - код в порядке. Один быстрый и простой способ проверить xml - открыть его в Internet Explorer.

David Hall 22.11.2008 04:22

Вы уверены, что в теле установлена ​​кодировка utf-16, а не что-то другое? Кроме того, действительно ли ваша строка тела экранирована, например body = "<? xml version = \" 1.0 \ "encoding = \" utf-16 \ "?> \ n <Report> Это тест </Report>";

Zach Burlingame 23.06.2009 20:36
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
64
2
181 074
9

Ответы 9

Я понял. Прочтите документацию 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);

Чтение документации MSDN для XmlDocument.LoadXml (String) здесь: msdn.microsoft.com/en-us/library/… сводка метода гласит: «Загружает XML-документ из указанной строки». Однако, как вы заявили, в нем говорится: «Если вы хотите загрузить из Stream, String, TextReader или XmlReader, используйте метод Load вместо этого метода». Кроме того, если вы посмотрите на XmlDocument.Load (String), он говорит: URL-адрес файла, содержащего XML-документ для загрузки. «URL-адрес может быть либо локальным файлом, либо URL-адресом HTTP (веб-адресом)». (больше в другом комментарии)

Zach Burlingame 23.06.2009 20:07

Я считаю, что предполагаемая цель строки «Если вы хотите загрузить из Stream, String, ...» на самом деле «Если вы хотите загрузить из Stream, File, ...», но у них есть String, потому что загрузка из Файл принимает строковый параметр в качестве имени файла. Я не верю, что их намерение состоит в том, «если вы хотите загрузить XmlDocument из строки в памяти, используйте Load». В конце концов, это заявленная цель LoadXml (String)! Хотя ваше решение обеспечивает обходной путь, я не думаю, что оно решает актуальную заявленную проблему (которая у меня тоже есть) с помощью XmlDocument.LoadXml (String).

Zach Burlingame 23.06.2009 20:12

Фон

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

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

System.Xml.XmlException: Data at the root level is invalid. Line 1, position 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 здесь:

Each Unicode character in a string is defined by a Unicode scalar value, also called a Unicode code point or the ordinal (numeric) value of the Unicode character. Each code point is encoded using UTF-16 encoding, and the numeric value of each element of the encoding is represented by a Char object.

Это означает, что когда вы передаете 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);

не забывайте ms.close ()

Zé Carlos 20.03.2013 15:17

Или используя оператор MemoryStream

DFTR 22.07.2014 00:08

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

XmlDocument bodyDoc = new XmlDocument();
bodyDoc.XMLResolver = null;
bodyDoc.Load(body);

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

var xdoc = new XmlDocument { XmlResolver = null };  
xdoc.LoadXml(xmlFragment);

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

Например:

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("sample.xml");

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

user2672332 04.04.2020 18:35

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

Я написал метод расширения, основанный на ответе Зака, также я расширил его, чтобы использовать кодировку в качестве параметра, позволяя использовать различные кодировки помимо 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);
        }
    }
}

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

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

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

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

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

Другие вопросы по теме