Метод XmlDocument.Load () не может декодировать € (евро)

У меня есть XML-документ file.xml, который закодирован в Iso-latin-15 (он же Iso-Latin-9)

<?xml version="1.0" encoding="iso-8859-15"?>
<root xmlns="http://stackoverflow.com/demo">
  <f>€.txt</f>
</root>

Из моего любимого текстового редактора я могу сказать, что этот файл правильно закодирован в Iso-Latin-15 (это не UTF-8).

Моя программа написана на C # и хочет извлечь элемент f.

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("file.xml"); 

В реальной жизни у меня есть XMLResolver для установки учетных данных. Но в основном мой код такой простой. Загрузка идет плавно, никаких исключений не возникало.

Теперь моя проблема, когда я извлекаю значение:

//xnsm is the XmlNameSpace manager
XmlNode n = xmlDoc.SelectSingleNode("//root/f", xnsm); 
if (n != null)
  String filename = n.InnerText;

Отладчик Visual Studio отображает filename = □.txt

Это может быть только ошибка Visual Studio. К сожалению, File.Exists(filename) возвращает false, тогда как файл действительно существует.

Что случилось?


person rds    schedule 09.12.2010    source источник
comment
Я дважды проверил кодировку с помощью Visual Studio.   -  person rds    schedule 09.12.2010
comment
Вы пробовали, если ошибка тоже возникает, если вы используете Stream, для которого вы устанавливаете кодировку вручную? Я был бы осторожен с такими утверждениями, как это может быть только ошибка Visual Studio ...   -  person Hinek    schedule 09.12.2010


Ответы (3)


Не используйте отладчик или консоль только для отображения строки как строки.

Вместо этого выгружайте содержимое строки по одному символу за раз. Например:

foreach (char c in filename)
{
    Console.WriteLine("{0}: {1:x4}", c, (int) c);
}

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

Используйте таблицы кодов Unicode для поиска указанных символов.

person Jon Skeet    schedule 09.12.2010
comment
Не совсем ответ, но это определенно хороший способ отладить эту ситуацию. Спасибо. Теперь я знаю, что проблемный персонаж - :0080. Это управляющий символ в Юникоде. Достаточно интересно, что это Euro sympo в Windows-CP1252. Я думаю, что строка должна быть реализована в Unicode внутри, это заставляет меня все больше и больше думать, что в реализации XmlDocument есть ошибка. - person rds; 09.12.2010
comment
@rds: Хорошо, теперь вы знаете, что он определенно не декодировал его должным образом. Следующая остановка: что в файле в байтах? А .NET вообще понимает iso-8859-15? - person Jon Skeet; 09.12.2010
comment
+1 Я подозреваю, что файл на самом деле закодирован в windows-1252, а не в ISO-8859-15 вообще. Отображается ли символ евро при просмотре в программе просмотра XML (например, в веб-браузере)? Windows и .NET поддерживают ISO-8859-15, но он используется очень редко. - person bobince; 09.12.2010
comment
Вывод: Да, входной файл имеет 0x80. - person rds; 09.12.2010
comment
@rds: Ага. Хорошо, это должно быть 0xA4 согласно en.wikipedia.org/wiki/ISO/IEC_8859- 15 - person Jon Skeet; 09.12.2010

Если я правильно помню, метод XmlDocument.Load(string) всегда предполагает UTF-8, независимо от кодировки XML.

Вам нужно будет создать StreamReader с правильной кодировкой и использовать это в качестве параметра.

xmlDoc.Load(new StreamReader(
                     File.Open("file.xml"), 
                     Encoding.GetEncoding("iso-8859-15"))); 

РЕДАКТИРОВАТЬ:

Я только что наткнулся на KB308061 от Microsoft. Есть интересный отрывок:

Укажите объявление кодировки в разделе XML-объявления XML-документа. Например, следующее объявление указывает, что документ имеет формат кодировки Unicode UTF-16:

<?xml version="1.0" encoding="UTF-16"?>

Обратите внимание, что это объявление определяет только формат кодировки XML-документа и не изменяет фактический формат кодирования данных и не контролирует его.

person VVS    schedule 09.12.2010
comment
Спасибо за указатель. Однако я не могу предположить, что входной файл - это Iso-8859-15. - person rds; 09.12.2010
comment
Я так понимаю, что метод Load() обращает внимание на заголовок xml, как я и думал. В противном случае их реализация XmlDocument была бы отстойной. - person rds; 09.12.2010

  1. Правильно ли ваш xml определяет свою кодировку? encoding = "iso-8859-15" .. это Iso-latin-15

  2. В идеале вы должны поместить свой контент в элемент CDATA ... чтобы xml выглядел как <f><![CDATA[€.txt]]></f>

  3. В идеале вы также должны экранировать все специальные символы с помощью эквивалентных значений в кодировке url (или http-кодировке), потому что xml обычно используется для связи через http.

Я не знаю точного кода выхода для € .. но это будет что-то в этом роде

<f><![CDATA[%3E.txt]]></f>

Вышеупомянутое должно обеспечить правильную передачу € через xml.

person Community    schedule 09.12.2010
comment
В идеале вы должны поместить свой код в блоки кода, чтобы они впоследствии правильно отображались. - person Lucero; 09.12.2010
comment
Разделы CDATA ничего не делают для решения проблем с кодированием. Фактически, поскольку они содержат только необработанные символьные данные, они не позволяют вам использовать символьные ссылки, такие как &#x20AC;, что вы, похоже, собираетесь использовать в (3). - person bobince; 09.12.2010
comment
Да (2) специально не решает проблему, но с намерением защитить больше специальных символов, если они будут в значении .. В (3) я намеренно поместил пример формата кодирования URL% 3E (не €), который должен быть декодирован после извлечения значения с помощью кода из xml. - person ; 09.12.2010