Шестнадцатеричное значение 0x00 является недопустимым символом

Я создаю XML-документ из StringBuilder, в основном что-то вроде:

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 и вставка его в текстовую панель).

Возможно, существуют различия в версиях sql-сервера (в 2008 году это будет неудачно, 2005 год будет работать) и сортировки. Не уверены, что это может быть причиной?

Но точно так же код и данные будут иногда терпеть неудачу. Любые идеи, в которых проблема?

Ответы

Ответ 1

Без ваших фактических данных или источника нам будет сложно диагностировать, что происходит неправильно. Однако я могу сделать несколько предложений:

  • 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 начинались с спецификации.

Ответ 2

В моем случае это потребовало некоторого рытья, но нашло его.

Мой контекст

Я просматриваю журналы ошибок/ошибок с веб-сайта, используя Elmah. Elmah возвращает состояние сервера в момент исключения, в виде большого XML-документа. Для нашего механизма отчетности я довольно хорошо печатаю XML с XmlWriter.

Во время атаки на веб-сайт я заметил, что некоторые 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();
}

LESSON LEARNED: санировать за незаконные байты с помощью связанного объекта html, если ваши входящие данные кодируются html при записи.

Ответ 3

Чтобы добавить к Sonz ответ выше, мы работаем для нас.

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

Ответ 4

Я также получаю ту же ошибку в приложении ASP.NET, когда я сохранил некоторые данные Unicode (хинди) в файле Web.config и сохранил его с кодировкой "Unicode".

Он исправил ошибку для меня, когда я сохранил файл Web.config с кодировкой "UTF-8".

Ответ 5

В качестве своего рода позднего ответа:

У меня возникла проблема с 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

Проблема возникает, если вы выделяете массив байтов, который по крайней мере на 1 байт больше, чем файл RDL (XML).

В частности, я использовал конвертер С# в vb.net, который преобразовал

  btBuffer = new byte[fstrStream.Length];

в

  btBuffer = New Byte(fstrStream.Length) {}

Но поскольку в С# число обозначает NUMBER OF ELEMENTS в массиве, а в VB.NET это число обозначает UPPER BOUND массива, у меня был избыточный байт, вызывающий эту ошибку.

Итак, решение проблемы просто:

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

Ответ 6

Я использую IronPython здесь (так же, как .NET API) и читаю файл как UTF-8, чтобы правильно обрабатывать спецификацию, исправил проблему для меня:

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)))