2012-06-14 257 views
16

我從一個StringBuilder生成一個XML文檔,基本上是這樣的:
十六進制值爲0x00是無效字符

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 
} 

所有數據來自數據庫。 最近,我已經受夠了錯誤的幾個問題:

Hexadecimal value 0x00 is a invalid character, line 1, position nnnnn

但它並不一致。 有時候一些'空白'的數據會起作用。 '錯誤'的數據適用於某些電腦,但不適用於其他電腦。

在數據庫中,數據始終是空白字符串。它從來不是'空' ,在XML文件中,它出現爲< data>< /data>,即在開始和結束之間沒有字符。 (但不確定這是否可以依賴,因爲我從「立即」窗口將它拉到vis studio並粘貼到文本板中)。

SQL服務器的版本可能存在差異(2008年會出現故障,2005年可能會出現故障),也可能會進行整理。 不確定這些是否有可能的原因?

但是完全相同的代碼和數據有時會失敗。問題出在哪裏?

+0

是否真如後的「<」出來的'< data>< /data>'*用空格*?如果是這樣,你的XML已損壞,不能被信任。丟棄它。所有的。 –

+2

@DourHighArch我發現唯一可行的方法就是將它燒掉。 – Sprague

回答

17

如果沒有您的實際數據或來源,我們很難診斷出現問題的原因。不過,我可以提出幾點建議:

  • 的Unicode NUL(0×00)是違法的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開頭。

4

當我在Web.config文件中保存了一些unicode數據(印地語)並使用「Unicode」編碼保存時,我在ASP.NET應用程序中也遇到同樣的錯誤。

它修復了我用「UTF-8」編碼保存Web.config文件時的錯誤。

9

在我的情況下,它採取了一些挖掘,但發現它。

我的上下文

我期待在異常/錯誤日誌使用ELMAH網站。 Elmah以大XML文檔的形式返回異常時服務器的狀態。對於我們的報表引擎,我用XmlWriter漂亮地打印XML。

在網站攻擊期間,我注意到一些xml不解析並且正在接收這個異常。

非分辨率:我將文檔轉換爲byte[]並將其消毒爲0x00,但未找到。

當我掃描的XML文檔,我發現:

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

有編碼爲HTML實體&#x0;的NULL字節!

解決方案:要解決的編碼,我加載到我的XmlDocument改爲面前&#x0;值,因爲加載它會創建NULL字節,這將是很難從對象清理動作。這裏是我的整個流程:

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入境編碼。

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#中的數字表示所述陣列中元件的數量,並且在VB.NET,這個數字表示數組的UPPER BOUND,我有一個多餘的字節,導致這個錯誤。

所以,問題的解決方案很簡單:

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

爲了增加Sonz的回答上面,下面爲我們工作。

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

從Outlook郵件項目獲取RTF正文並嘗試將其序列化爲XML後,此工作適用於我。 –

+0

在對話中添加了更多內容。如果您必須跨越消費設備需要您發送 和您的設備平臺使用xslt轉換成目標格式..你可以使用像這樣的佔位符(你可以稱之爲任何東西),並在發送之前將其替換。 – hWright

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))) 
相關問題