【问题标题】:How to prevent System.Xml.XmlException: Invalid character in the given encoding如何防止 System.Xml.XmlException:给定编码中的字符无效
【发布时间】:2011-11-26 02:18:14
【问题描述】:

我有一个用 C# 编写的 Windows 桌面应用程序,它遍历存储在磁盘上并由第 3 方程序创建的一堆 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"/>

【问题讨论】:

  • 能否包含失败文件的第 52327 行,以便我们查看导致异常的内容是什么?
  • 刚刚添加。对我来说毫无意义。
  • 请发布实际上会导致问题的实际 XML。
  • 下一行或上一行怎么样?他们有适当数量的字符吗?此外,您可以尝试在至少可以显示无效字符占位符的编辑器中打开(如果您还没有的话)(即 NoteTab Pro,我只建议这样做,因为它是我唯一知道的)。
  • 最流行的网络浏览器会验证您的 XML 并准确显示找到无效内容的位置。

标签: c# xml linq-to-xml


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • 选项 2 是高路。编写软件以生成 XML 文档的供应商应该提供有效的 XML。他们的错误可能不仅会影响您,还会影响其他客户。
    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

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

      当我遇到这种情况时,那里有重音字符之类的东西:坟墓、锐音符、变音符号等等。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-09
        • 2014-10-14
        • 1970-01-01
        • 1970-01-01
        • 2012-04-20
        • 1970-01-01
        相关资源
        最近更新 更多