如何防止System.Xml.XmlException:给定编码中的字符无效

我有一个用C#编写的Windows桌面应用程序,它循环存储在磁盘上并由第三方程序创建的一堆XML文件。 大多数所有文件都由此语句后面的LINQ代码成功加载和处理:

XDocument xmlDoc = XDocument.Load(inFileName); List docList = (from d in xmlDoc.Descendants("DOCUMENT") select new DocMetaData { File = d.Element("FILE").SafeGetAttributeValue("filename") , Folder = d.Element("FOLDER").SafeGetAttributeValue("name") , ItemID = d.Elements("INDEX") .Where(i => (string)i.Attribute("name") == "Item ID(idmId)") .Select(i => (string)i.Attribute("value")) .FirstOrDefault() , Comment = d.Elements("INDEX") .Where(i => (string)i.Attribute("name") == "Comment(idmComment)") .Select(i => (string)i.Attribute("value")) .FirstOrDefault() , Title = d.Elements("INDEX") .Where(i => (string)i.Attribute("name") == "Title(idmName)") .Select(i => (string)i.Attribute("value")) .FirstOrDefault() , DocClass = d.Elements("INDEX") .Where(i => (string)i.Attribute("name") == "Document Class(idmDocType)") .Select(i => (string)i.Attribute("value")) .FirstOrDefault() } ).ToList(); 

…其中inFileName是一个完整的路径和文件名,例如:

  Y:\S2Out\B0000004\Pet Tab\convert.B0000004.Pet Tab.xml 

但是一些文件会导致这样的问题:

 System.Xml.XmlException: Invalid character in the given encoding. Line 52327, position 126. at System.Xml.XmlTextReaderImpl.Throw(Exception e) at System.Xml.XmlTextReaderImpl.Throw(String res, String arg) at System.Xml.XmlTextReaderImpl.InvalidCharRecovery(Int32& bytesCount, Int32& charsCount) at System.Xml.XmlTextReaderImpl.GetChars(Int32 maxCharsCount) at System.Xml.XmlTextReaderImpl.ReadData() at System.Xml.XmlTextReaderImpl.ParseAttributeValueSlow(Int32 curPos, Char quoteChar, NodeData attr) at System.Xml.XmlTextReaderImpl.ParseAttributes() at System.Xml.XmlTextReaderImpl.ParseElement() at System.Xml.XmlTextReaderImpl.ParseElementContent() at System.Xml.XmlTextReaderImpl.Read() at System.Xml.Linq.XContainer.ReadContentFrom(XmlReader r) at System.Xml.Linq.XContainer.ReadContentFrom(XmlReader r, LoadOptions o) at System.Xml.Linq.XDocument.Load(XmlReader reader, LoadOptions options) at System.Xml.Linq.XDocument.Load(String uri, LoadOptions options) at System.Xml.Linq.XDocument.Load(String uri) at CBMI.WinFormsUI.GridForm.processFile(StreamWriter oWriter, String inFileName, Int32 XMLfileNumber) in C:\ProjectsVS2010\CBMI.LatitudePostConverter\CBMI.LatitudePostConverter\CBMI.WinFormsUI\GridForm.cs:line 147 at CBMI.WinFormsUI.GridForm.btnProcess_Click(Object sender, EventArgs e) in C:\ProjectsVS2010\CBMI.LatitudePostConverter\CBMI.LatitudePostConverter\CBMI.WinFormsUI\GridForm.cs:line 105 

XML文件看起来像这样(此示例仅显示2个DOCUMENT元素,但有很多):

                       

LINQ语句有其自身的复杂性,但我认为它的工作正常; 失败的是LOAD。 我已经查看了XDocument Load的各种构造函数,并且我已经研究了抛出此exception的其他一些问题,但我对如何防止这种情况感到困惑。

最后,在第52327行,126位,在无法加载的文件中,似乎第52327行的这些数据不应该导致问题(并且最后一个字符位于第103位!

  

为了控制编码(一旦你知道它是什么),你可以使用接受StreamLoad方法覆盖来加载文件。

然后,您可以针对您的文件创建一个新的StreamReader ,在构造函数中指定相应的Encoding

例如,要使用西欧编码打开文件,请替换问题中的以下代码行:

 XDocument xmlDoc = XDocument.Load(inFileName); 

使用此代码:

 XDocument xmlDoc = null; using (StreamReader oReader = new StreamReader(inFileName, Encoding.GetEncoding("ISO-8859-1"))) { xmlDoc = XDocument.Load(oReader); } 

支持的编码列表可以在MSDN文档中找到。

不确定这是否是您的情况,但这可能与给定编码的无效字节序列有关。 示例: http : //en.wikipedia.org/wiki/UTF-8#Invalid_byte_sequences 。

尝试在加载时从文件中过滤无效序列。

引用的文件包含对文件名有效的字符,但在XML属性中无效。 你有几个选择。

  1. 您可以更改文件名并重新运行第三方脚本。
  2. 您可以与供应商合作,提供可以安全编码违规字符的补丁。
  3. 您可以在处理之前预先validationXML文档并删除有问题的条目。

因为XmlDocument在遇到未编码的字符时会立即加载整个内容,因此会中止整个过程。 如果你想处理你能做的事情并跳过/记录duff位,请查看XmlTextReader。 从Filestream加载的XmlTextReader将一次加载一个节点,因此它也将使用更少的内存。 你甚至可以聪明地将事情拆分并平行处理。

当我有这个时,就像那里的重音人物一样:坟墓,尖锐,变形金刚等等。

我没有任何自动化过程,所以通常我只是在Visual Studio中加载文件并编辑坏人,直到没有任何波形。 这个理论虽然合理。