为啥包含 XML 标头时 C# XmlDocument.LoadXml(string) 会失败?
Posted
技术标签:
【中文标题】为啥包含 XML 标头时 C# XmlDocument.LoadXml(string) 会失败?【英文标题】:Why does C# XmlDocument.LoadXml(string) fail when an XML header is included?为什么包含 XML 标头时 C# XmlDocument.LoadXml(string) 会失败? 【发布时间】:2010-09-23 13:33:40 【问题描述】:有谁知道为什么下面的代码示例失败并出现 XmlException “根级别的数据无效。第 1 行,位置 1。”
var body = "<?xml version="1.0" encoding="utf-16"?><Report> ......"
XmlDocument bodyDoc = new XmlDocument();
bodyDoc.LoadXml(body);
【问题讨论】:
Dan 是对的 - 代码很好。检查 xml 的一种快速简便的方法是在 Internet Explorer 中打开它 您确定将正文中的编码设置为 utf-16 而不是别的吗?此外,您的身体字符串是否真的逃脱了,例如body = "\n背景
虽然您的问题确实将编码设置为 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 文档标头中指定的编码可能不同。例如:
<?xml version="1.0" encoding="utf-8"?>
来自字符串 here 的 MSDN 文档:
字符串中的每个 Unicode 字符都是 由 Unicode 标量值定义, 也称为 Unicode 代码点或 的序数(数字)值 Unicode 字符。每个代码点是 使用 UTF-16 编码进行编码,并且 的每个元素的数值 编码由 Char 表示 对象。
这意味着当您通过 XmlDocument.LoadXml() 传递带有 XML 标头的字符串时,它必须说编码是 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);
【讨论】:
别忘了 ms.close() 或在 MemoryStream 上使用语句【参考方案2】:简单有效的解决方案:不要使用LoadXml()
方法,而是使用Load()
方法
例如:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("sample.xml");
【讨论】:
这更容易做和理解。我的文档没有任何 xml 标头。【参考方案3】:我想通了。阅读 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);
【讨论】:
在此处阅读 XmlDocument.LoadXml(String) 的 MSDN 文档:msdn.microsoft.com/en-us/library/… 方法摘要指出:“从指定的字符串加载 XML 文档。”但是,正如您所说,它确实说:“如果您想从 Stream、String、TextReader 或 XmlReader 加载,请使用 Load 方法而不是此方法。”此外,如果您查看 XmlDocument.Load(String) 它会显示:包含要加载的 XML 文档的文件的 URL。 “URL 可以是本地文件,也可以是 HTTP URL(Web 地址)。” (更多内容在另一条评论中) 我相信“如果您想从流、字符串...加载”这行的预期目的实际上是“如果您想从流、文件...加载”但他们有 String 因为从文件加载需要文件名的字符串参数。我不相信他们的意图是“如果您想从内存中的字符串加载 XmlDocument,请使用 Load”。毕竟,这就是 LoadXml(String) 的既定目的!虽然您的解决方案确实提供了解决方法,但我认为它不能解决 XmlDocument.LoadXml(String) 的实际陈述问题(我也有)。【参考方案4】:试试这个:
XmlDocument bodyDoc = new XmlDocument();
bodyDoc.XMLResolver = null;
bodyDoc.Load(body);
【讨论】:
【参考方案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 文件从绝对路径切换到相对路径时,我遇到了同样的问题。 以下解决了加载和使用相对源路径问题。 使用在 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);
【讨论】:
【参考方案8】:简单的线:
bodyDoc.LoadXml(new MemoryStream(Encoding.Unicode.GetBytes(body)));
【讨论】:
【参考方案9】:我遇到了同样的问题,因为我上传的 XML 文件是使用 UTF-8-BOM(UTF-8 字节顺序标记)编码的。
在 Notepad++ 中将编码切换为 UTF-8,并且能够在代码中加载 XML 文件。
【讨论】:
以上是关于为啥包含 XML 标头时 C# XmlDocument.LoadXml(string) 会失败?的主要内容,如果未能解决你的问题,请参考以下文章
从 dbus xml 生成文件时,如何告诉 qmake 包含标头?