为什么包含XML头时C#XmlDocument.LoadXml(string)失败?

有没有人有任何想法,为什么以下代码示例失败,带有一个XmlException“在根层面的数据是无效的,行1,位置1。

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

背景

虽然你的问题确实有编码设置为UTF-16,你没有正确的string转义,所以我不确定你是否确实把string转换成你的问题。

我遇到了同样的例外:

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

问题

问题是,string在内部以UTF-16的forms存储在.NET中,但是在XML文档头中指定的编码可能不同。 例如:

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

从这里的string的MSDN文档:

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

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

解决scheme

这个问题的解决scheme是确保在你传递Load或LoadXml方法时使用的编码与你在XML标题中所说的相符。 在我上面的示例中,将XML标题更改为状态UTF-16或者以UTF-8编码input,并使用XmlDocument.Load方法之一 。

下面是演示如何使用MemoryStream使用定义UTF-8编码XML文档的string(当然,存储了UTF-16 .NETstring)构buildXmlDocument的示例代码。

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

简单而有效的解决scheme:使用Load()方法代替使用LoadXml() Load()方法

例如:

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

尝试这个:

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

我想到了。 阅读MSDN文档,它说从string读取时使用.Load,而不是LoadXml。 发现这个工作100%的时间。 奇怪的是,使用StringReader会导致问题。 我认为主要的原因是这是一个Unicode编码的string,可能会导致问题,因为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); 

这对我工作:

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

这真的救了我的一天。

我已经写了一个基于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); } } } 

我从xml文件从绝对path切换到相对path时遇到同样的问题。 以下解决了加载和使用相对源path问题。 使用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); 

简单的线条:

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