Шестнадцатеричное значение 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�.htm" />
</item>
...
Был nul-байт, закодированный как объект html �
!!!
РАЗРЕШЕНИЕ:. Чтобы исправить кодировку, я заменил значение �
перед загрузкой в мой XmlDocument
, потому что при загрузке он создаст нулевой байт, и его будет трудно дезинфицировать из объект. Здесь весь мой процесс:
XmlDocument xml = new XmlDocument();
details.Xml = details.Xml.Replace("�", "[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("�", "[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)))