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

时间:2012-06-14 15:50:27

标签: .net sql-server xml

我正在从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

但它不一致。 有时候一些“空白”数据会起作用。 “有缺陷”的数据适用于某些PC,但不适用于其他PC。

在数据库中,数据始终为空字符串。永远不会'无效' 在XML文件中,它以< data>< /data>形式出现,即打开和关闭之间没有字符。 (但不确定这是否可以依赖,因为我从'立即'窗口拉出它是工作室并将其粘贴到文本板中。)

sql server的版本可能存在差异(2008年它将失败,2005年将会运行)和排序规则。 不确定这些是否可能是原因造成的?

但完全相同的代码和数据有时会失败。问题出在哪里?

7 个答案:

答案 0 :(得分:23)

如果没有您的实际数据或来源,我们很难诊断出现了什么问题。但是,我可以提出一些建议:

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

鉴于你写的内容,我怀疑将数据库数据转换为XML的任何内容都被破坏了;它正在传播非XML字符。

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

如果转换器输出看起来不错,则问题出在您的XML使用者身上;它在某处插入非XML字符。您必须将您的消费过程分解为单独的步骤,检查每一步的输出,并缩小引入坏字符的内容。

更新:我自己就是这样做的一个例子!发生的事情是,生产者将XML编码为UTF16,消费者期望UTF8。由于UTF16使用0x00作为所有ASCII字符的高字节而UTF8不使用,因此消费者将每个第二个字节视为NUL。在我的情况下,我可以更改编码,但建议所有XML有效负载都以BOM开头。

答案 1 :(得分:10)

在我的情况下,它花了一些挖掘,但发现了它。

我的情境

我正在使用Elmah查看网站上的异常/错误日志。 Elmah以大型XML文档的形式返回异常时的服务器状态。对于我们的报告引擎,我使用XmlWriter打印XML。

在网站攻击期间,我注意到有些xmls没有解析并且收到此'.', hexadecimal value 0x00, is an invalid character.例外。

非解决方案:我将文档转换为byte[]并将其清理为0x00,但没有找到。

当我扫描xml文档时,我发现了以下内容:

...
<form>
...
<item name="SomeField">
   <value
     string="C:\boot.ini&#x0;.htm" />
 </item>
...

将nul字节编码为html实体&#x0; !!!

解决方法:为了修复编码,我在将&#x0;值加载到XmlDocument之前替换了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(); } 值,因为加载它会创建nul字节,这将很难从物体上消毒它。这是我的整个过程:

{{1}}

经验教训:使用关联的html实体清理非法字节,如果您的传入数据在输入时进行了html编码。

答案 2 :(得分:6)

要添加Sonz的上述答案,以下是为我们工作的。

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

答案 3 :(得分:4)

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

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

答案 4 :(得分:3)

作为一个迟到的回答:

上传报告时,我遇到了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#中数字表示数组中的NUMEMENT OF ELEMENTS,而在VB.NET中,该数字表示数组的UPPER BOUND,我有一个多余的字节,导致此错误。

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

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

答案 5 :(得分:1)

我在这里使用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)))

答案 6 :(得分:0)

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

1.查看开发工具,我发现在分配给sheet collection {Hoja1}, {Cartera}, {JennyG, {MariaD, ...

2.然后我看到工作表名称中的最后一个字符 '}' 应该丢失到算法过程中的任何时间,以从 DataTable 对象分配工作表名称。

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

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