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

本文关键字:编码 无效 字符 System 何防止 Xml XmlException | 更新日期: 2023-09-27 18:16:00

我有一个用c#编写的Windows桌面应用程序,它循环遍历存储在磁盘上的一堆XML文件,这些文件是由第三方程序创建的。以下语句后面的LINQ代码可以成功加载和处理大多数文件:

XDocument xmlDoc = XDocument.Load(inFileName);
List<DocMetaData> 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<DocMetaData>();

…其中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元素,但是有很多):

<?xml version="1.0" ?>
<DOCUMENTCOLLECTION>
   <DOCUMENT>
       <FILE filename="e:'S2Out'B0000005'General'D003712420.0001.pdf" outputpath="e:'S2Out'B0000005'General"/>
       <ANNOTATION filename=""/>
       <INDEX name="Comment(idmComment)" value=""/>
       <INDEX name="Document Class(idmDocType)" value="General"/>
       <INDEX name="Item ID(idmId)" value="003712420"/>
       <INDEX name="Original File Name(idmDocOriginalFile)" value="Matrix Aligning 603.24 Criteria to Petition Pages.pdf"/>
       <INDEX name="Title(idmName)" value="Matrix for 603.24"/>
       <FOLDER name="/Accreditation/PASBVE/2004-06"/>
   </DOCUMENT>
   <DOCUMENT>
       <FILE filename="e:'S2Out'B0000005'General'D003712442.0001.pdf" outputpath="e:'S2Out'B0000005'General"/>
       <ANNOTATION filename=""/>
       <INDEX name="Comment(idmComment)" value=""/>
       <INDEX name="Document Class(idmDocType)" value="General"/>
       <INDEX name="Item ID(idmId)" value="003712442"/>
       <INDEX name="Original File Name(idmDocOriginalFile)" value="Contacts at NDU.pdf"/>
       <INDEX name="Title(idmName)" value="Contacts at NDU"/>
       <FOLDER name="/Accreditation/NDU/2006-12/Self-Study"/>
   </DOCUMENT>

LINQ语句有自己的复杂性,但我认为它工作得很好;是LOAD失败了。我看过XDocument Load的各种构造函数,我研究了一些其他问题,抛出了这个异常,但我对如何防止这种情况感到困惑。

最后,在加载失败的文件中的第52327行,位置126处,似乎第52327行的数据不应该导致问题(最后一个字符位于位置103!)

<FILE filename="e:'S2Out'B0000004'Pet Tab'D003710954.0001.pdf" outputpath="e:'S2Out'B0000004'Pet Tab"/>

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

为了控制编码(一旦您知道它是什么),您可以使用接受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文档中找到。

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

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

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

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

因为XmlDocument一旦遇到未编码的字符就加载整个内容,所以它会中止整个过程。如果您想处理您所能处理的内容并跳过/记录不重要的部分,请查看XmlTextReader。从Filestream加载的XmlTextReader将一次加载一个节点,因此它也将使用更少的内存。你甚至可以聪明一点,把事情分开,并行处理。

当我有这个的时候,它是像重音字符一样的东西:grave, acutes, umlauts,等等。

我没有任何自动化的过程,所以通常我只是在Visual Studio中加载文件并编辑坏的部分,直到没有留下任何弯曲。不过这个理论是合理的。