十六进制值0x00是一个无效字符。

39
我正在使用 StringBuilder 生成一个 XML 文档,基本上就像这样:
string.Format("<text><row>{0}</row><col>{1}</col><textHeight>{2}</textHeight><textWidth>{3}</textWidth><data>{4}</data><rotation>{5}</rotation></text>

稍后,类似这样:

XmlDocument document = new XmlDocument();
document.LoadXml(xml);
XmlNodeList labelSetNodes = document.GetElementsByTagName("labels");
for (int index = 0; index < labelSetNodes.Count; index++)
{
    //do something
}
所有数据都来自数据库。最近我遇到了一个错误:

十六进制值0x00是无效字符,行1,位置nnnnn

但是这并不一致。有时候一些'空白'数据会起作用。 有问题的数据在某些电脑上正常工作,而在其他电脑上却不行。

在数据库中,数据始终为空字符串。它从未为“null”,并且在XML文件中,它显示为< data>< /data>,即打开和关闭之间没有字符。(但我不确定是否可以依赖此信息,因为我正在从Vis Studio的“immediate”窗口中获取它,并将其粘贴到Textpad中)。

可能存在SQL Server版本(2008会失败,而2005会成功)和排序方面的差异。不确定这些是否可能是导致问题的原因?

但是完全相同的代码和数据有时会失败。您有什么想法这个问题出在哪里?

它真的会输出为“< data>< /data>”吗?如果是这样,你的XML已经损坏,不能被信任。丢弃它。全部都要丢弃。 - Dour High Arch
5
我发现唯一可靠的方法就是烧掉它。 - Sprague
7个回答

36

没有提供实际数据或来源,我们很难诊断出问题所在。但我可以给出几个建议:

  • Unicode NUL (0x00) 在所有版本的 XML 中都是非法的,验证解析器必须拒绝包含它的输入。
  • 尽管如上所述,实际世界中未经验证的 XML 可以包含任何类型的垃圾格式错误字节。
  • XML 1.1 允许零宽度和不打印的控制字符(除 NUL 外),因此您无法在文本编辑器中查看 XML 1.1 文件并告诉它包含了哪些字符。

根据您的描述,我怀疑将数据库数据转换为 XML 的过程有问题;它正在传递非 XML 字符。

创建一些带有非 XML 字符(NUL、DEL、控制字符等)的数据库条目,并对其运行 XML 转换器。将 XML 输出到文件中并在十六进制编辑器中查看。如果其中包含非 XML 字符,则您的转换器有问题。修复它,或者如果您不能修复它,则创建一个预处理程序,拒绝具有这些字符的输出。

如果转换器的输出看起来很好,那么问题就出现在您的 XML 消费者中;它在某个地方插入了非 XML 字符。您将需要将消费过程分解成单独的步骤,检查每个步骤的输出,并缩小引入错误字符的位置。

检查文件编码(对于 UTF-16)

更新:我自己遇到了这个问题的示例!问题在于生产者将 XML 编码为 UTF16,而消费者期望使用 UTF8。由于 UTF16 对于所有 ASCII 字符都使用 0x00 作为高字节,而 UTF8 不是这样,因此消费者会将每隔一个字节视为 NUL。在我的情况下,我可以更改编码方式,但建议所有 XML 负载均以 BOM 开始。


1
这里有一个解决UTF-16问题的不错的技巧:https://dev59.com/J18d5IYBdhLWcg3w41gp#M6qfEYcBWogLw_1b8S7a - Ohad Schneider
1
我在PowerShell中为我的Web应用程序创建了一个配置.xml文件,使用"" > myConfigFile.xml初始化空文件后,将配置粘贴到文件中。这将默认编码设置为UTF-16... - CJBS
我刚遇到了这个问题:我的问题是我正在使用System.Encoding.Unicode.GetBytes("some string")解析字符串。当我改为使用System.Encoding.Utf8.GetBytes("some string")时,它开始工作了。你的情况可能会有所不同。 - ubienewbie

17
在我的情况下,需要一番搜索才找到了它。 我的背景 我正在使用Elmah查看网站的异常/错误日志。 Elmah以大型XML文档的形式返回服务器在异常发生时的状态。 对于我们的报告引擎,我使用XmlWriter将XML格式化输出。
在网站遭受攻击期间,我注意到某些xml无法解析,并收到了这个异常:'.', hexadecimal value 0x00, is an invalid character. 非解决方案:我将文档转换为byte[]并对其进行了0x00的清理,但未发现任何问题。
当我扫描XML文档时,我发现以下内容:
...
<form>
...
<item name="SomeField">
   <value
     string="C:\boot.ini&#x0;.htm" />
 </item>
...

有一个以HTML实体编码的空字节&#x0;!!!

解决方法: 为了修复编码,我在将其加载到我的XmlDocument之前替换了&#x0;值,因为加载它会创建空字节,并且很难从对象中进行清理。以下是整个过程:

XmlDocument xml = new XmlDocument();
details.Xml = details.Xml.Replace("&#x0;", "[0x00]");  // in my case I want to see it, otherwise just replace with ""
xml.LoadXml(details.Xml);

string formattedXml = null;

// I have this in a helper function, but for this example I have put it in-line
StringBuilder sb = new StringBuilder();
XmlWriterSettings settings = new XmlWriterSettings {
    OmitXmlDeclaration = true,
    Indent = true,
    IndentChars = "\t",
    NewLineHandling = NewLineHandling.None,
};
using (XmlWriter writer = XmlWriter.Create(sb, settings)) {
    xml.Save(writer);
    formattedXml = sb.ToString();
}

教训:如果您的输入数据经过HTML编码,请使用相关的HTML实体来消毒非法字节。

注:本文涉及IT技术相关内容。

9

补充Sonz的回答,以下是我们使用的方法。

//Instead of 
XmlString.Replace("&#x0;", "[0x00]");
// use this
XmlString.Replace("\x00", "[0x00]");

在从Outlook邮件项获取RTF正文并尝试将其序列化为XML后,这种方法对我有效。 - Matthew Lock
如果您需要跨设备平台进行通信,其中消费设备需要您发送 并且您使用XSLT转换为目标格式,那么您可以使用类似<newline/>(您可以随意命名)的占位符,并在发送之前将其替换为最终结果。 - user1788742
在我的情况下,XML中存在 ��������������������������������� 数据,因此它无法解析。我将其删除并更新了XML,解析问题得到解决。 - Akshay Anand

4

当我在Web.config文件中保存一些Unicode数据(印地语)并使用“Unicode”编码保存时,我在ASP.NET应用程序中也遇到了同样的错误。

当我使用“UTF-8”编码保存Web.config文件时,它为我修复了这个错误。


4
作为一个晚一些的回答:
当我上传报告时,我遇到了SSRS ReportService2005.asmx的问题。
    Public Shared Sub CreateReport(ByVal strFileNameAndPath As String, ByVal strReportName As String, ByVal strReportingPath As String, Optional ByVal bOverwrite As Boolean = True)
        Dim rs As SSRS_2005_Administration_WithFOA = New SSRS_2005_Administration_WithFOA
        rs.Credentials = ReportingServiceInterface.GetMyCredentials(strCredentialsURL)
        rs.Timeout = ReportingServiceInterface.iTimeout
        rs.Url = ReportingServiceInterface.strReportingServiceURL
        rs.UnsafeAuthenticatedConnectionSharing = True

        Dim btBuffer As Byte() = Nothing

        Dim rsWarnings As Warning() = Nothing
        Try
            Dim fstrStream As System.IO.FileStream = System.IO.File.OpenRead(strFileNameAndPath)
            btBuffer = New Byte(fstrStream.Length - 1) {}
            fstrStream.Read(btBuffer, 0, CInt(fstrStream.Length))
            fstrStream.Close()
        Catch ex As System.IO.IOException
            Throw New Exception(ex.Message)
        End Try

        Try
            rsWarnings = rs.CreateReport(strReportName, strReportingPath, bOverwrite, btBuffer, Nothing)

            If Not (rsWarnings Is Nothing) Then
                Dim warning As Warning
                For Each warning In rsWarnings
                    Log(warning.Message)
                Next warning
            Else
                Log("Report: {0} created successfully with no warnings", strReportName)
            End If

        Catch ex As System.Web.Services.Protocols.SoapException
            Log(ex.Detail.InnerXml.ToString())
        Catch ex As Exception
            Log("Error at creating report. Invalid server name/timeout?" + vbCrLf + vbCrLf + "Error Description: " + vbCrLf + ex.Message)
            Console.ReadKey()
            System.Environment.Exit(1)
        End Try
    End Sub ' End Function CreateThisReport

问题出现在您分配的字节数组比RDL(XML)文件大至少1个字节时。
具体来说,我使用了一个C#转换器将代码转换为vb.net。
  btBuffer = new byte[fstrStream.Length];

转换为

  btBuffer = New Byte(fstrStream.Length) {}

但由于在C#中,数字表示数组中的元素数量,在VB.NET中,该数字表示数组的上限,因此我多了一个字节,导致了这个错误。

所以问题的解决方案很简单:

  btBuffer = New Byte(fstrStream.Length - 1) {}

2
我在这里使用IronPython(与.NET API相同),并以UTF-8的格式读取文件,以便正确处理BOM,这样问题就得到了解决。
xmlFile = Path.Combine(directory_str, 'file.xml')
doc = XPathDocument(XmlTextReader(StreamReader(xmlFile.ToString(), Encoding.UTF8)))

使用XmlDocument同样有效:

doc = XmlDocument()
doc.Load(XmlTextReader(StreamReader(xmlFile.ToString(), Encoding.UTF8)))

0

我遇到了同样的问题,当我尝试保存文件时,整个代码都是完美的,但在最后一个过程中,出现了以下错误信息:
"'.', 十六进制值0x00是无效字符。"

1.在开发工具中查看时,我发现赋给工作表集合的名称中存在{Hoja1},{Cartera},{JennyG},{MariaD}等字符。

2.然后我注意到工作表名称的末尾字符“}”应该在算法处理过程中的某个时间丢失,以便为工作表从 DataTable 对象中分配名称。

3.在名称属性上,工作表的真实名称是"MariaD\0\0\0\0\0\0\0\0\0\0\0\0\0\0",属性名称中的隐藏字符"\0"不受支持。

4.最后,解决方案是将所有工作表名称中的当前字符替换为空字符串""。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接