ReadXMLFile неверная кодировка

Общие вопросы программирования, алгоритмы и т.п.

Модератор: Модераторы

ReadXMLFile неверная кодировка

Сообщение baiguzov » 27.04.2009 19:10:40

Функцией ReadXMLFile читаю xml-файл в кодировке UTF-8, первая строка файла

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

но при чтении функцией node.Attributes.GetNamedItem('attribute_name').NodeValue данные приходят в кодировке cp1251. Можно ли это как-то исправить? Может быть где-то можно указать чтобы не xml не конвертировался?

Или как альтернатива подскажите чем ещё можно прочитать xml файл в utf-8 кодировке?

PS Пробовал искать ответ на этом форуме и на англоязычном, а также гуглил и яндексил, но ответа увы не нашёл.
baiguzov
новенький
 
Сообщения: 14
Зарегистрирован: 13.01.2009 20:30:58

Re: ReadXMLFile неверная кодировка

Сообщение Sergei I. Gorelkin » 27.04.2009 20:03:24

Все данные в DOM имеют тип widestring и кодировку utf-16, вне зависимости от того, что написано в первой строке файла.
Если свойства DOM присваивать переменным типа AnsiString, то компилятор добавит неявное преобразование в кодовую страницу системы, в случае русской Windows это будет cp1251.
Поэтому лучше работать с переменными типа WideString (при этом не будет перекодировок, код будет компактнее и быстрее), или, если нужно таки получить utf-8 - то использовать функции utf8encode() и utf8decode().
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1395
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: ReadXMLFile неверная кодировка

Сообщение shade » 27.04.2009 20:15:26

Жаль, что FPC не различает типы AnsiString и UTF8String :(
Аватара пользователя
shade
энтузиаст
 
Сообщения: 879
Зарегистрирован: 21.02.2006 20:15:48
Откуда: http://shamangrad.net/

Re: ReadXMLFile неверная кодировка

Сообщение baiguzov » 27.04.2009 20:29:22

Вот этот вариант UTF8Encode(node.Attributes.GetNamedItem('attribute_name').NodeValue) выдаёт результат в UTF-8. Спасибо за совет.
baiguzov
новенький
 
Сообщения: 14
Зарегистрирован: 13.01.2009 20:30:58

Re: ReadXMLFile неверная кодировка

Сообщение Vladimir » 17.08.2009 13:58:17

Столкнулся с аналогичной проблемой и не только я http://www.lazarus.freepascal.org/index.php/topic,6409.0.html .
Обрабатываю xml в UTF-8, записываю в переменную WideString, например, значение атриубута с русскими символами, получаю текст в win-1251
...
var
NodeText:WideString;
begin
...
NodeText:=CNode.Attributes.GetNamedItem('name').TextContent;
...
end;

Приходится перекодировать в UTF-8 с моиощью UTF8Encode(). Как я понял, это баг последних версий Lazarus, проблема не в компоненте. Или я ошибаюсь? Баг, конечно, крайне неприятный :(
Vladimir
незнакомец
 
Сообщения: 8
Зарегистрирован: 17.08.2009 13:40:45

Re: ReadXMLFile неверная кодировка

Сообщение Mr.Smart » 17.08.2009 14:23:14

Это не баг!
Непосредственное присваивания строки WideString к String преобразует символы юникода к локальной однобайтовой кодеровке системы.
В данном случае к кодеровке Win-1251.
Для преобразования в UTF-8 существуют специальные функции.
Mr.Smart
долгожитель
 
Сообщения: 1796
Зарегистрирован: 29.03.2008 01:01:11
Откуда: из леса!

Re: ReadXMLFile неверная кодировка

Сообщение Vladimir » 17.08.2009 14:25:06

А где здесь присваивание WideString к String? переменная в которую записывается значение атрибута типа WideString
Vladimir
незнакомец
 
Сообщения: 8
Зарегистрирован: 17.08.2009 13:40:45

Re: ReadXMLFile неверная кодировка

Сообщение Mr.Smart » 17.08.2009 14:27:20

Vladimir писал(а):А где здесь присваивание WideString к String? переменная в которую записывается значение атрибута типа WideString

Тогда вопрос. Как вы определили, что у вас в переменной именно кодировка Win-1251?
Mr.Smart
долгожитель
 
Сообщения: 1796
Зарегистрирован: 29.03.2008 01:01:11
Откуда: из леса!

Re: ReadXMLFile неверная кодировка

Сообщение Vladimir » 17.08.2009 14:37:23

Под отладчиком посмотрел. Кроме того при попытке присвоить значение этой переменной свойству любого компонента имеем в этом свойстве пустую строку (собственно так проблема и обнаружилась), после перекодировки с помощью UTF8Encode() тоже свойство содержит нормальный русский текст
Vladimir
незнакомец
 
Сообщения: 8
Зарегистрирован: 17.08.2009 13:40:45

Re: ReadXMLFile неверная кодировка

Сообщение Mr.Smart » 17.08.2009 14:38:44

WideString - это 2-х байтная строка UCS-2
UTF8String = AnsiString = String - это одно байтная строка. В которой текст хранится либо в кодировке UTF-8 либо в ANSI.
Mr.Smart
долгожитель
 
Сообщения: 1796
Зарегистрирован: 29.03.2008 01:01:11
Откуда: из леса!

Re: ReadXMLFile неверная кодировка

Сообщение Vladimir » 17.08.2009 14:49:22

кодировка UTF-8 содержит, насколько мне известно и однобайтные и многобайтные символы.

И какой из этого вывод? Какого типа должна быть переменная, чтобы избежать преобразования в локаль системы?
Vladimir
незнакомец
 
Сообщения: 8
Зарегистрирован: 17.08.2009 13:40:45

Re: ReadXMLFile неверная кодировка

Сообщение Mr.Smart » 17.08.2009 14:53:00

Преобразование строк:
WideString(Unicode,UCS2)<->Ansi
Простое присваивание
Код: Выделить всё
...
var
sw: WideString;
sa: String;
...
sa:=sw;
...

Unicode <-> UTF-8
Код: Выделить всё
UTF8Encode()
UTF8Decode()

Ansi <-> UTF-8
Код: Выделить всё
AnsiToUTF8()
UTF8ToAnsi()


p.s. Все строки LCL используют кодировку UTF-8!

Добавлено спустя 8 минут 50 секунд:
Vladimir писал(а):кодировка UTF-8 содержит, насколько мне известно и однобайтные и многобайтные символы.

Содержит, но особенность этой кодировки в том, что символ с кодом #0 неможет встретится поэтому для хранения используется обычный тип String
Vladimir писал(а):И какой из этого вывод? Какого типа должна быть переменная, чтобы избежать преобразования в локаль системы?

В данный момент для преобразования в UTF8 вам недостаточно будет просто присвоить одну строку другой:
Код: Выделить всё
...
var
w: WideString;
u: UTF8String; // можно использовать и AnsiString и String
...
  u:=w; // Вызовет неявное преобразование Unicode->Ansi
  u:=UTF8Encode(w); // Преобразование Unicode->UTF-8
...


p.s. В будущем обещают выделить тип UTF8String в отдельный. И возможно появится неявное преобразование Unicode в UTF-8 и Ansi в UTF-8 простым присваиванием! Но это будет ещё нескоро... :wink:
Mr.Smart
долгожитель
 
Сообщения: 1796
Зарегистрирован: 29.03.2008 01:01:11
Откуда: из леса!

Re: ReadXMLFile неверная кодировка

Сообщение Vladimir » 17.08.2009 15:09:09

Как преобразовать в общем-то понятно. Не ясно, почему возникает необходимость преобразования? Потому что свойства LCL в UTF-8, а WideString - это UTF-16 ?

В целом выглядит странно. Парсим файл в UTF-8 (другие кодировки ReadXMLFile() не принимает, в итоге его же элементы перекодируем в тот же UTF-8

Добавлено спустя 11 минут 48 секунд:
Да, посмотрел, в частности параметр TTreeNodes.AddChild в который я передаю значение атрибута - типа string. Спасибо, Mr.Smart!

Текущую реализацию работы с xml в лазарус сложно признать удобной :(
Vladimir
незнакомец
 
Сообщения: 8
Зарегистрирован: 17.08.2009 13:40:45

Re: ReadXMLFile неверная кодировка

Сообщение Sergei I. Gorelkin » 17.08.2009 16:11:22

Vladimir писал(а):Как преобразовать в общем-то понятно. Не ясно, почему возникает необходимость преобразования? Потому что свойства LCL в UTF-8, а WideString - это UTF-16 ?

Да, поэтому.
Модуль для работы с xml написан в соответствии со спецификацией w3.org, которая предусматривает использование строк с двухбайтными элементами. Ноги этой спецификации растут откуда-то из мира java, насколько я понимаю.
ReadXMLFile понимает не только utf-8, но и utf-16 и iso8859-1, а при условии подключения к программе модуля xmliconv (в винде - xmliconv_windows) - и все остальные кодировки.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1395
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: ReadXMLFile неверная кодировка

Сообщение Vladimir » 17.08.2009 20:14:41

Sergei I. Gorelkin писал(а):Модуль для работы с xml написан в соответствии со спецификацией w3.org, которая предусматривает использование строк с двухбайтными элементами. Ноги этой спецификации растут откуда-то из мира java, насколько я понимаю.


Спасибо! Выбор 2-х байтовых строк вполне логичен, универсальность это - хорошо. Только учитывая, обсуждаемую склонность компилятора перекодировать текст в локаль, получается несколько неуклюже, и не очевидно, особенно для новичков.
Если я правильно понял, переменные типа string могут содержать как одно так и двух байтовый текст, почему бы не рассмотреть вариант возврата значений в виде string, но в 2-х байтовом виде? Или принципиально использование именно UTF-16?
Vladimir
незнакомец
 
Сообщения: 8
Зарегистрирован: 17.08.2009 13:40:45

След.

Вернуться в Общее

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 6

Рейтинг@Mail.ru