为什么包含XML头时C#XmlDocument.LoadXml(字符串)会失败?

时间:2008-11-22 01:04:35

标签: c# .net xml

有没有人知道为什么以下代码示例因XmlException而失败“根级别的数据无效。第1行,第1位。”

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

9 个答案:

答案 0 :(得分:116)

背景

虽然您的问题确实将编码设置为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);

问题

问题是字符串在.NET内部存储为UTF-16,但XML文档头中指定的编码可能不同。 E.g:

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

来自字符串here的MSDN文档:

  

字符串中的每个Unicode字符都是   由Unicode标量值定义,   也称为Unicode代码点或   的序数(数字)值   Unicode字符。每个代码点都是   使用UTF-16编码编码,和   每个元素的数值   编码由Char表示   对象

这意味着当您使用XML标头传递XmlDocument.LoadXml()时,必须说编码是UTF-16。否则,实际的基础编码将与标头中报告的编码不匹配,并将导致抛出XmlException。

解决方案

此问题的解决方案是确保在传递Load或LoadXml方法的任何内容中使用的编码与您在XML标头中的说法相匹配。在上面的示例中,要么将XML标头更改为UTF-16状态,要么将输入编码为UTF-8并使用XmlDocument.Load methods之一。

下面是示例代码,演示如何使用MemoryStream使用定义UTF-8编码XML文档的字符串构建XmlDocument(当然,存储为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);

答案 1 :(得分:28)

简单有效的解决方案:使用LoadXml()方法

,而不是使用Load()方法

例如:

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

答案 2 :(得分:7)

试试这个:

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

答案 3 :(得分:6)

我明白了。阅读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);

答案 4 :(得分:2)

这对我有用:

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

答案 5 :(得分:2)

这真的挽救了我的一天。

我已经根据Zach的答案编写了一个扩展方法,我也将其扩展为使用编码作为参数,允许使用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);
        }
    }
}

答案 6 :(得分:1)

我从xml文件的绝对路径切换到相对路径时遇到了同样的问题。 以下内容解决了加载和使用相对源路径问题的问题。 使用在xaml中定义的XmlDataProvider(在代码中也应该是可能的):

    <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);

答案 7 :(得分:0)

简单的一行:

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

答案 8 :(得分:0)

我遇到了同样的问题,因为我上传的XML文件是使用UTF-8-BOM(UTF-8字节顺序标记)编码的。

在Notepad ++中将编码切换为UTF-8,并能够在代码中加载XML文件。