ReadXMLFile неверная кодировка
Модератор: Модераторы
ReadXMLFile неверная кодировка
Функцией ReadXMLFile читаю xml-файл в кодировке UTF-8, первая строка файла
<?xml version="1.0" encoding="UTF-8"?>
но при чтении функцией node.Attributes.GetNamedItem('attribute_name').NodeValue данные приходят в кодировке cp1251. Можно ли это как-то исправить? Может быть где-то можно указать чтобы не xml не конвертировался?
Или как альтернатива подскажите чем ещё можно прочитать xml файл в utf-8 кодировке?
PS Пробовал искать ответ на этом форуме и на англоязычном, а также гуглил и яндексил, но ответа увы не нашёл.
<?xml version="1.0" encoding="UTF-8"?>
но при чтении функцией node.Attributes.GetNamedItem('attribute_name').NodeValue данные приходят в кодировке cp1251. Можно ли это как-то исправить? Может быть где-то можно указать чтобы не xml не конвертировался?
Или как альтернатива подскажите чем ещё можно прочитать xml файл в utf-8 кодировке?
PS Пробовал искать ответ на этом форуме и на англоязычном, а также гуглил и яндексил, но ответа увы не нашёл.
- Sergei I. Gorelkin
- энтузиаст
- Сообщения: 1409
- Зарегистрирован: 24.07.2005 14:40:41
- Откуда: Зеленоград
Все данные в DOM имеют тип widestring и кодировку utf-16, вне зависимости от того, что написано в первой строке файла.
Если свойства DOM присваивать переменным типа AnsiString, то компилятор добавит неявное преобразование в кодовую страницу системы, в случае русской Windows это будет cp1251.
Поэтому лучше работать с переменными типа WideString (при этом не будет перекодировок, код будет компактнее и быстрее), или, если нужно таки получить utf-8 - то использовать функции utf8encode() и utf8decode().
Если свойства DOM присваивать переменным типа AnsiString, то компилятор добавит неявное преобразование в кодовую страницу системы, в случае русской Windows это будет cp1251.
Поэтому лучше работать с переменными типа WideString (при этом не будет перекодировок, код будет компактнее и быстрее), или, если нужно таки получить utf-8 - то использовать функции utf8encode() и utf8decode().
- shade
- энтузиаст
- Сообщения: 879
- Зарегистрирован: 21.02.2006 19:15:48
- Откуда: http://shamangrad.net/
- Контактная информация:
Жаль, что FPC не различает типы AnsiString и UTF8String 
Вот этот вариант UTF8Encode(node.Attributes.GetNamedItem('attribute_name').NodeValue) выдаёт результат в UTF-8. Спасибо за совет.
Столкнулся с аналогичной проблемой и не только я 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, проблема не в компоненте. Или я ошибаюсь? Баг, конечно, крайне неприятный
Обрабатываю xml в UTF-8, записываю в переменную WideString, например, значение атриубута с русскими символами, получаю текст в win-1251
...
var
NodeText:WideString;
begin
...
NodeText:=CNode.Attributes.GetNamedItem('name').TextContent;
...
end;
Приходится перекодировать в UTF-8 с моиощью UTF8Encode(). Как я понял, это баг последних версий Lazarus, проблема не в компоненте. Или я ошибаюсь? Баг, конечно, крайне неприятный
Это не баг!
Непосредственное присваивания строки WideString к String преобразует символы юникода к локальной однобайтовой кодеровке системы.
В данном случае к кодеровке Win-1251.
Для преобразования в UTF-8 существуют специальные функции.
Непосредственное присваивания строки WideString к String преобразует символы юникода к локальной однобайтовой кодеровке системы.
В данном случае к кодеровке Win-1251.
Для преобразования в UTF-8 существуют специальные функции.
А где здесь присваивание WideString к String? переменная в которую записывается значение атрибута типа WideString
Vladimir писал(а):А где здесь присваивание WideString к String? переменная в которую записывается значение атрибута типа WideString
Тогда вопрос. Как вы определили, что у вас в переменной именно кодировка Win-1251?
Под отладчиком посмотрел. Кроме того при попытке присвоить значение этой переменной свойству любого компонента имеем в этом свойстве пустую строку (собственно так проблема и обнаружилась), после перекодировки с помощью UTF8Encode() тоже свойство содержит нормальный русский текст
WideString - это 2-х байтная строка UCS-2
UTF8String = AnsiString = String - это одно байтная строка. В которой текст хранится либо в кодировке UTF-8 либо в ANSI.
UTF8String = AnsiString = String - это одно байтная строка. В которой текст хранится либо в кодировке UTF-8 либо в ANSI.
кодировка UTF-8 содержит, насколько мне известно и однобайтные и многобайтные символы.
И какой из этого вывод? Какого типа должна быть переменная, чтобы избежать преобразования в локаль системы?
И какой из этого вывод? Какого типа должна быть переменная, чтобы избежать преобразования в локаль системы?
Преобразование строк:
WideString(Unicode,UCS2)<->Ansi
Простое присваивание
Unicode <-> UTF-8
Ansi <-> UTF-8
p.s. Все строки LCL используют кодировку UTF-8!
Добавлено спустя 8 минут 50 секунд:
Содержит, но особенность этой кодировки в том, что символ с кодом #0 неможет встретится поэтому для хранения используется обычный тип String
В данный момент для преобразования в UTF8 вам недостаточно будет просто присвоить одну строку другой:
p.s. В будущем обещают выделить тип UTF8String в отдельный. И возможно появится неявное преобразование Unicode в UTF-8 и Ansi в UTF-8 простым присваиванием! Но это будет ещё нескоро...
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 простым присваиванием! Но это будет ещё нескоро...
Как преобразовать в общем-то понятно. Не ясно, почему возникает необходимость преобразования? Потому что свойства LCL в UTF-8, а WideString - это UTF-16 ?
В целом выглядит странно. Парсим файл в UTF-8 (другие кодировки ReadXMLFile() не принимает, в итоге его же элементы перекодируем в тот же UTF-8
Добавлено спустя 11 минут 48 секунд:
Да, посмотрел, в частности параметр TTreeNodes.AddChild в который я передаю значение атрибута - типа string. Спасибо, Mr.Smart!
Текущую реализацию работы с xml в лазарус сложно признать удобной
В целом выглядит странно. Парсим файл в UTF-8 (другие кодировки ReadXMLFile() не принимает, в итоге его же элементы перекодируем в тот же UTF-8
Добавлено спустя 11 минут 48 секунд:
Да, посмотрел, в частности параметр TTreeNodes.AddChild в который я передаю значение атрибута - типа string. Спасибо, Mr.Smart!
Текущую реализацию работы с xml в лазарус сложно признать удобной
- Sergei I. Gorelkin
- энтузиаст
- Сообщения: 1409
- Зарегистрирован: 24.07.2005 14:40:41
- Откуда: Зеленоград
Vladimir писал(а):Как преобразовать в общем-то понятно. Не ясно, почему возникает необходимость преобразования? Потому что свойства LCL в UTF-8, а WideString - это UTF-16 ?
Да, поэтому.
Модуль для работы с xml написан в соответствии со спецификацией w3.org, которая предусматривает использование строк с двухбайтными элементами. Ноги этой спецификации растут откуда-то из мира java, насколько я понимаю.
ReadXMLFile понимает не только utf-8, но и utf-16 и iso8859-1, а при условии подключения к программе модуля xmliconv (в винде - xmliconv_windows) - и все остальные кодировки.
Sergei I. Gorelkin писал(а):Модуль для работы с xml написан в соответствии со спецификацией w3.org, которая предусматривает использование строк с двухбайтными элементами. Ноги этой спецификации растут откуда-то из мира java, насколько я понимаю.
Спасибо! Выбор 2-х байтовых строк вполне логичен, универсальность это - хорошо. Только учитывая, обсуждаемую склонность компилятора перекодировать текст в локаль, получается несколько неуклюже, и не очевидно, особенно для новичков.
Если я правильно понял, переменные типа string могут содержать как одно так и двух байтовый текст, почему бы не рассмотреть вариант возврата значений в виде string, но в 2-х байтовом виде? Или принципиально использование именно UTF-16?
