2012-06-14 24 views
16

sto generando un documento XML da uno StringBuilder, in fondo qualcosa di simile:
esadecimale valore 0x00 è un carattere non valido

string.Format("<text><row>{0}</row><col>{1}</col><textHeight>{2}</textHeight><textWidth>{3}</textWidth><data>{4}</data><rotation>{5}</rotation></text> 

Più tardi, qualcosa di simile:

XmlDocument document = new XmlDocument(); 
document.LoadXml(xml); 
XmlNodeList labelSetNodes = document.GetElementsByTagName("labels"); 
for (int index = 0; index < labelSetNodes.Count; index++) 
{ 
    //do something 
} 

Tutti i dati provengono da un Banca dati. Recentemente ho avuto alcuni problemi con l'errore:

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

Ma non è coerente. A volte funzionano alcuni dati "vuoti". I dati "difettosi" funzionano su alcuni PC, ma non su altri.

Nel database, i dati sono sempre una stringa vuota. Non è mai 'nullo' e nel file XML, risulta come < data>< /data>, cioè senza carattere tra l'apertura e la chiusura. (ma non sono sicuro se questo possa essere invocato mentre lo sto tirando dalla finestra "immediata" è vis studio e lo incolla nel textpad).

Ci sono probabilmente differenze nelle versioni di SQL Server (2008 è dove fallirebbe, 2005 funzionerebbe) e anche le regole di confronto. Non sei sicuro che qualcuno di questi sia una probabile causa?

Ma a volte lo stesso codice e i dati a volte falliscono. Qualche idea in cui si trova il problema?

+0

lo fa davvero venire fuori come '' < data>< /data> * con uno spazio dopo il '<' *? Se è così, il tuo XML è corrotto e non può essere considerato attendibile. Scarta. Tutto. –

+2

@DourHighArch Ho trovato l'unico modo sicuro per masterizzarlo. – Sprague

risposta

17

Senza i tuoi dati effettivi o la tua fonte, sarà difficile per noi diagnosticare cosa non va. Tuttavia, posso fornire alcuni suggerimenti:

  • Unicode NUL (0x00) è illegale in tutte le versioni di XML e i parser di convalida devono rifiutare l'input che lo contiene.
  • Nonostante quanto sopra; L'XML non convalidato nel mondo reale può contenere qualsiasi tipo di byte non formattato di rifiuti immateriali immaginabili.
  • XML 1.1 consente caratteri di controllo a larghezza zero e non stampabile (tranne NUL), quindi non è possibile guardare un file XML 1.1 in un editor di testo e indicare quali caratteri contiene.

Dato quello che hai scritto, ho il sospetto che qualsiasi conversione dei dati del database in XML sia interrotta; sta propagando caratteri non XML.

Creare alcune voci del database con caratteri non XML (NUL, DEL, caratteri di controllo, ecc.) Ed eseguire il convertitore XML su di esso. Esegui l'XML in un file e guardalo in un editor esadecimale. Se questo contiene caratteri non XML, il tuo convertitore è rotto. Risolvilo o, se non puoi, crea un preprocessore che rifiuta l'output con tali caratteri.

Se l'uscita del convertitore sembra buona, il problema è nel consumer XML; sta inserendo da qualche parte caratteri non XML. Dovrai interrompere il processo di consumo in passaggi separati, esaminare l'output ad ogni passaggio e restringere l'introduzione dei caratteri non validi.

Aggiornamento: mi sono imbattuto in un esempio di questo me stesso! Quello che stava accadendo è che il produttore stava codificando l'XML come UTF16 e il consumatore si aspettava UTF8. Poiché UTF16 utilizza 0x00 come byte alto per tutti i caratteri ASCII e UTF8 no, il consumatore vedeva ogni secondo byte come NUL. Nel mio caso, potrei cambiare la codifica, ma ho suggerito che tutti i payload XML iniziano con una distinta base.

4

Ho anche ricevuto lo stesso errore in un'applicazione ASP.NET quando ho salvato alcuni dati Unicode (Hindi) nel file Web.config e l'ho salvato con la codifica "Unicode".

Ha corretto l'errore per me quando ho salvato il file Web.config con la codifica "UTF-8".

9

Nel mio caso, ci sono voluti degli scavi, ma l'ho trovato.

mio Contesto

sto guardando logs/errore di eccezione dal sito web utilizzando Elmah. Elmah restituisce lo stato del server al momento dell'eccezione, sotto forma di un grande documento XML. Per il nostro motore di report, stampo piuttosto bene l'XML con XmlWriter.

Durante un attacco al sito Web, ho notato che alcuni xml non stavano analizzando e stava ricevendo questa eccezione '.', hexadecimal value 0x00, is an invalid character..

NON RISOLUZIONE: Ho convertito il documento in byte[] e lo ha disinfettato di 0x00, ma non ne ha trovato.

Quando ho scansionato il documento XML, ho trovato il seguente:

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

C'era il byte nul codificato come entità HTML &#x0; !!!

Risoluzione: Per fissare la codifica, ho sostituito il valore &#x0; prima di caricarla nel mio XmlDocument, Dato che il carico si creerà il byte nul e sarà difficile per igienizzare dall'oggetto. Ecco il mio intero processo:

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(); 
} 

Lezione imparata: disinfettare per byte illegali che utilizzano l'entità html associato, se i dati in ingresso viene html codificato in entrata.

3

come una specie di risposta in ritardo:

Ho avuto questo problema con SSRS ReportService2005.asmx durante il caricamento di un report.

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 

Il problema si verifica quando si assegna un array di byte che è almeno 1 byte più grande del file RDL (XML).

Specificamente, ho usato un C# convertitore vb.net, che ha convertito

btBuffer = new byte[fstrStream.Length]; 

in

btBuffer = New Byte(fstrStream.Length) {} 

Ma poiché in C# il numero indica il numero di elementi nella matrice, e VB.NET, quel numero indica UPPER BOUND dell'array, ho avuto un byte in eccesso, causando questo errore.

Quindi la soluzione del problema è semplicemente:

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

Per aggiungere alla risposta di Sonz sopra, seguito ha lavorato per noi.

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

Questo ha funzionato per me dopo aver ottenuto il corpo RTF da un elemento di Outlook Mail e aver tentato di serializzarlo in XML –

+0

aggiungendo ancora di più alla conversazione .. se devi passare attraverso piattaforme di dispositivi in ​​cui il dispositivo che consuma ha bisogno di inviare e tu usa xslt per trasformarlo nel formato di destinazione .. puoi usare un segnaposto come (puoi chiamarlo qualsiasi cosa) e sostituirlo alla fine prima di inviarlo. – hWright

1

sto utilizzando IronPython qui (lo stesso di API .NET) e leggendo il file come UTF-8, al fine di gestire correttamente il BOM ha risolto il problema per me:

xmlFile = Path.Combine(directory_str, 'file.xml') 
doc = XPathDocument(XmlTextReader(StreamReader(xmlFile.ToString(), Encoding.UTF8))) 

Sarebbe funzionano anche con il XmlDocument:

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