Игнорирование указанной кодировки при десериализации XML

Я пытаюсь прочитать некоторый XML, полученный от внешнего интерфейса через сокет. Проблема в том, что в XML-заголовке указана неправильная кодировка (там iso-8859-1, а там utf-16BE). Документировано, что кодировка utf-16BE, но видимо забыли выставить правильную кодировку.

Чтобы игнорировать кодировку при десериализации, я использую StringReader следующим образом:

    private static T DeserializeXmlData<T>(byte[] xmlData)
    {
        var xmlString = Encoding.BigEndianUnicode.GetString(xmlData);
        using (var reader = new StringReader(xmlString))
        {
            reader.ReadLine(); // Eat header line
            using (var xmlReader = XmlReader.Create(reader))
            {
                var serializer = new XmlSerializer(typeof(T));
                return (T)serializer.Deserialize(xmlReader);
            }
        }
    }

Вышеупомянутое на самом деле работает нормально, но мне не нравится часть, где я просто пропускаю строку заголовка, вызывая ReadLine. Есть ли менее хрупкий способ обойти кодировку, указанную в XML-заголовке?

Решение с помощью StreamReader

Используя StreamReader, я могу переопределить кодировку, указанную в XML-заголовке. Указание XmlReaderSettings.IgnoreProcessingInstructions или нет не имело никакого значения. Интересно, что StreamReader игнорирует указанную кодировку, если находит метку порядка байтов Unicode.

Резюме:

  • Если XmlReader инициализируется TextReader, кодировка XML-заголовка игнорируется.
  • Если используется StringReader, XmlReader завершается ошибкой, если существует метка порядка байтов Unicode.
  • Если используется StreamReader, метка порядка байтов Unicode переопределяет кодировку StreamReader.
  • XmlReaderSettings.IgnoreProcessingInstructions = true не имеет значения при использовании TextReader.

В заключение, наиболее надежным решением, по-видимому, является использование StreamReader, поскольку он использует метку порядка байтов, если она присутствует.

    private static T DeserializeXmlData<T>(byte[] xmlData)
    {
        using (var xmlDataStream = new MemoryStream(xmlData))
        {
            using (var reader = new StreamReader(xmlDataStream, Encoding.BigEndianUnicode))
            {
                using (var xmlReader = XmlReader.Create(reader))
                {
                    var serializer = new XmlSerializer(typeof (T));
                    return (T) serializer.Deserialize(xmlReader);
                }
            }
        }
    }

person Holstebroe    schedule 27.10.2010    source источник


Ответы (2)


Я думаю, что я бы просто использовал StreamReader, созданный с правильной кодировкой, и передал бы его методу XmlReader.Create(TextStream):

 using (var sr = new StreamReader(@"c:\temp\bad.xml", Encoding.BigEndianUnicode)) {
     using (var xr = XmlReader.Create(sr, new XmlReaderSettings())) {
         // etc...
     }
 }
person Hans Passant    schedule 27.10.2010

Если нет других соответствующих инструкций по обработке, вы можете просто игнорировать их, установив XmlReaderSettings.IgnoreProcessingInstructions.

person DaVinci    schedule 27.10.2010
comment
Здорово! Как бы я тогда указал истинную кодировку? (XmlReader, основанный на StringReader, создает исключение, даже если для параметра IgnoreProcessingInstructions установлено значение true). - person Holstebroe; 27.10.2010