如果字符串以部分开头,则将xml字符串解析为xml文档会失败

我有一个XML文件,开头像这样:

   

当我运行以下代码时:

 byte[] fileContent = //gets bytes string stringContent = Encoding.UTF8.GetString(fileContent); XDocument xml = XDocument.Parse(stringContent); 

我得到以下XmlException:

根级别的数据无效。 第1行,第1位。

删除版本和编码节点可以解决问题。 为什么? 如何正确处理这个xml?

如果您只有字节,则可以将字节加载到流中:

 XmlDocument oXML; using (MemoryStream oStream = new MemoryStream(oBytes)) { oXML = new XmlDocument(); oXML.Load(oStream); } 

或者,您可以在加载XML之前将字节转换为字符串(假设您知道编码):

 string sXml; XmlDocument oXml; sXml = Encoding.UTF8.GetString(oBytes); oXml = new XmlDocument(); oXml.LoadXml(sXml); 

我已经将我的示例显示为与.NET 2.0兼容,如果您使用的是.NET 3.5,则可以使用XDocument而不是XmlDocument

将字节加载到流中:

 XDocument oXML; using (MemoryStream oStream = new MemoryStream(oBytes)) using (XmlTextReader oReader = new XmlTextReader(oStream)) { oXML = XDocument.Load(oReader); } 

将字节转换为字符串:

 string sXml; XDocument oXml; sXml = Encoding.UTF8.GetString(oBytes); oXml = XDocument.Parse(sXml); 

我首先想到的是,从.NET字符串类型解析XML时,编码是Unicode。 看来,虽然XDocument的解析对此非常宽容。

问题实际上与UTF8前同步码/字节顺序标记(BOM)有关,它是一个三字节签名, 可选地存在于UTF-8流的开头。 这三个字节是关于流中使用的编码的提示。

您可以通过在System.Text.Encoding类的实例上调用GetPreamble方法来确定编码的前导码。 例如:

 // returns { 0xEF, 0xBB, 0xBF } byte[] preamble = Encoding.UTF8.GetPreamble(); 

前导码应该由XmlTextReader正确处理,所以只需从XmlTextReader加载XDocument

 XDocument xml; using (var xmlStream = new MemoryStream(fileContent)) using (var xmlReader = new XmlTextReader(xmlStream)) { xml = XDocument.Load(xmlReader); } 

为什么要打扰将文件作为字节序列读取,然后在xml文件中将其转换为字符串? 只需离开框架为您加载并处理编码:

 var xml = XDocument.Load("test.xml"); 

您是否在XML的开头有一个字节顺序标记 (BOM),它是否与您的编码匹配? 如果你砍掉你的标题,你也会砍掉BOM,如果这不正确,那么随后的解析可能会有效。

您可能需要在字节级别检查文档以查看BOM。

试试这个:

 int startIndex = xmlString.IndexOf('<'); if (startIndex > 0) { xmlString = xmlString.Remove(0, startIndex); }