Был у меня метод серилизующий объекты моего типа в xml и имел такой вид:
public string serializeToString(MyObject item)
{
System.Xml.Serialization.XmlSerializer writer = new System.Xml.Serialization.XmlSerializer(typeof(MyObject));
StringWriter textWriter = new StringWriter();
writer.Serialize(textWriter, item);
return writer.ToString();
}
Все нормально работает, но мне хотелось чтобы результирующий xml был в кодировке cp 1251. Ок, казалось бы просто указываем для writer'a кодировку и все. Как бы не так. После гугления и матюков метод приобрел следующий вид:
public string serializeToString(MyObject item)
{
XmlWriterSettings wrSettings = new XmlWriterSettings();
wrSettings.Encoding = Encoding.GetEncoding(1251);
MemoryStream memoryStream = new MemoryStream();
System.Xml.Serialization.XmlSerializer writer = new System.Xml.Serialization.XmlSerializer(typeof(MyObject));
XmlWriter textWriter = XmlWriter.Create(memoryStream, wrSettings);
writer.Serialize(textWriter, item);
memoryStream.Position = 0;
StreamReader sr = new StreamReader(memoryStream);
return sr.ReadToEnd();
}
То есть нарисовались еще три абсолютно не нужных мне объекта. Знатоки и архитекторы библиотек, объясните мне почему нельзя было просто дать возможность указывать кодировку для объектов типа XmlSerializer? Что это за жесть такая, почему я должен создавать кучу объектов просто для того чтобы серилизовать объект в xml? Спасибо большое заранее.
D> public string serializeToString(MyObject item)
D>
Все как бы круто, только string — это по определению набор двухбайтовых символов в UNICODE, поэтому понятие "кодировка" для System.String в данном контексте бессмысленно. "Кодировка" приобретает смысл если XML сериализуется в какой-то внешний поток (файл, поток в памяти, LOB базы данных и так далее).
Здравствуйте, baranovda, Вы писали:
B>Здравствуйте, dmitritch, Вы писали:
D>>
D>> public string serializeToString(MyObject item)
D>>
B>Все как бы круто, только string — это по определению набор двухбайтовых символов в UNICODE, поэтому понятие "кодировка" для System.String в данном контексте бессмысленно. "Кодировка" приобретает смысл если XML сериализуется в какой-то внешний поток (файл, поток в памяти, LOB базы данных и так далее).
Спасибо, вы правы. Просто потом я пергоняю эту строку в массив байтов и гружу в базу, и мне надо чтобы в заголовке xml была явно указана кодировка cp1251, а не utf16 как у меня получалось в первом варианте.
Здравствуйте, dmitritch, Вы писали:
D>Спасибо, вы правы. Просто потом я пергоняю эту строку в массив байтов и гружу в базу, и мне надо чтобы в заголовке xml была явно указана кодировка cp1251, а не utf16 как у меня получалось в первом варианте.
Понятно. Если нужен заголовок, а XML нужен именно как поток байтов в однобайтовой кодировке, то думаю, что красивей всего будет выполнить преобразование XML при помощи самой простой XSL cразу в какой-нибудь поток (MemoryStream или типа того):
Здравствуйте, dmitritch, Вы писали:
D>Спасибо, вы правы. Просто потом я пергоняю эту строку в массив байтов и гружу в базу, и мне надо чтобы в заголовке xml была явно указана кодировка cp1251, а не utf16 как у меня получалось в первом варианте.
сделайте замену String.Replace ))
Здравствуйте, baranovda, Вы писали:
B>Здравствуйте, dmitritch, Вы писали:
D>>Спасибо, вы правы. Просто потом я пергоняю эту строку в массив байтов и гружу в базу, и мне надо чтобы в заголовке xml была явно указана кодировка cp1251, а не utf16 как у меня получалось в первом варианте.
B>Понятно. Если нужен заголовок, а XML нужен именно как поток байтов в однобайтовой кодировке, то думаю, что красивей всего будет выполнить преобразование XML при помощи самой простой XSL cразу в какой-нибудь поток (MemoryStream или типа того):
B><xsl:stylesheet ...> B> <xsl:output method="xml" encoding="windows-1251"> B> <xsl:template match="/"> B> <xsl:copy-of select="/" /> B> </xsl:template> B></xsl:stylesheet>
B>Кстати что за база? Современные СУБД сейчас почти все имеют типы данных для работы с XML и умеют его хранить не в блобах, а в структурированном виде.
Здравствуйте, dmitritch, Вы писали:
D>Спасибо, вы правы. Просто потом я пергоняю эту строку в массив байтов и гружу в базу, и мне надо чтобы в заголовке xml была явно указана кодировка cp1251, а не utf16 как у меня получалось в первом варианте.
Лучше сразу перегонять как массив байтов или поток.
Кодировка в заголовке должна соответствовать кодировке тела. Вы же сначала пишете в 1251, потом читаете из этого же потока как UTF-8 (проверить легко, см исходники).
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, dmitritch, Вы писали:
D>>Спасибо, вы правы. Просто потом я пергоняю эту строку в массив байтов и гружу в базу, и мне надо чтобы в заголовке xml была явно указана кодировка cp1251, а не utf16 как у меня получалось в первом варианте. S>Лучше сразу перегонять как массив байтов или поток.
S>Кодировка в заголовке должна соответствовать кодировке тела. Вы же сначала пишете в 1251, потом читаете из этого же потока как UTF-8 (проверить легко, см исходники).
Да, все заметил, действительно нужно сразу поток загонять в байты а не строку, потому что в строке кодировка получается utf 16.
Здравствуйте, dmitritch, Вы писали:
D>Oracle. Посмотрю насчет хранения xml.
В Oracle для работы с XML есть тип XMLType, умеет принимать в конструкторе well-formed XML. Но у него есть несколько неприятных багов: а) в 10g длина текста в текстовом узле не может превышать 32 кб (возможно, в 11 уже исправлено) б) он всегда преобразует внутренние строки к кодировке базы данных. Т.е. если база создана в CL8MSWIN1251, а ему будет передана строка NVARCHAR2, то он преобразует многобайтовую строку в однобайтовую и это приведет к утере данных. Но зато заголовок <?xml version= encoding= ?> он добавит сам, т.е. на клиенте никаких преобразований с кодировками делать не надо, надо лишь передать String через JDBC/ODBC/OLEDB/ADO.NET драйвер.
Здравствуйте, samius, Вы писали:
S>Здравствуйте, dmitritch, Вы писали:
D>>Спасибо, вы правы. Просто потом я пергоняю эту строку в массив байтов и гружу в базу, и мне надо чтобы в заголовке xml была явно указана кодировка cp1251, а не utf16 как у меня получалось в первом варианте. S>сделайте замену String.Replace ))
За такое — пожизненный эцих с гвоздями. Уж сколько раз спотыкались об эти расхождения заголовка и реального формата.
Здравствуйте, Mr.Delphist, Вы писали:
MD>Здравствуйте, samius, Вы писали:
D>>>Спасибо, вы правы. Просто потом я пергоняю эту строку в массив байтов и гружу в базу, и мне надо чтобы в заголовке xml была явно указана кодировка cp1251, а не utf16 как у меня получалось в первом варианте. S>>сделайте замену String.Replace ))
MD>За такое — пожизненный эцих с гвоздями. Уж сколько раз спотыкались об эти расхождения заголовка и реального формата.
Если использовать промежуточную дотнет строку, то разницу в форматах заметить будет проблематично.
А по делу — оно, конечно, сохранять в Stream и гнать в базу байты без использования промежуточной строки. Тут я согласен.
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, dmitritch, Вы писали:
D>>Спасибо, вы правы. Просто потом я пергоняю эту строку в массив байтов и гружу в базу, и мне надо чтобы в заголовке xml была явно указана кодировка cp1251, а не utf16 как у меня получалось в первом варианте. S>Лучше сразу перегонять как массив байтов или поток.
S>Кодировка в заголовке должна соответствовать кодировке тела. Вы же сначала пишете в 1251, потом читаете из этого же потока как UTF-8 (проверить легко, см исходники).
Кстати, вот еще вопрос всплыл. Как сделать чтобы опреденное свойство объекта не серилизовалось в xml. Про атрибут XmlIgnore знаю, проблема в том что атрибуты нельзя добавлять во время выполнения. А у меня для части объектов так, а для части хотелось бы по другому.
Здравствуйте, dmitritch, Вы писали:
D>Кстати, вот еще вопрос всплыл. Как сделать чтобы опреденное свойство объекта не серилизовалось в xml. Про атрибут XmlIgnore знаю, проблема в том что атрибуты нельзя добавлять во время выполнения. А у меня для части объектов так, а для части хотелось бы по другому.
1. XmlAttributes (см пример вот тут)
2. IXmlSerializable (если нужен полный контроль)
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, samius, Вы писали:
S>>Если использовать промежуточную дотнет строку, то разницу в форматах заметить будет проблематично.
S>Да ну S>
S> public class MyObject
S> {
S> public string A { get; set; }
S> }
S> static void Main(string[] args)
S> {
S> MyObject s = new MyObject { A = "Проверка" };
S> string s2 = serializeToString(s);
S> Console.WriteLine(s2); // <MyObject xmlns:....><A>��������</A></MyObject>
S> }
S>
Вот я как бы не чувствую что я не прав. Не прав код, который читает эту строку из стрима. Писали в стрим с одной кодировкой (1251), а читали — с другой (utf8). Потому и лажа. Если бы прочитали тоже с 1251, то все было бы как надо
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, samius, Вы писали:
S>>Если бы прочитали тоже с 1251, то все было бы как надо
S>По-моему строка xml в utf16 с заголовком "<?xml version="1.0" encoding="windows-1251"?>" вообще не похожа на "как надо"
Именно поэтому я и предлагал сделать String.Replace
Здравствуйте, samius, Вы писали:
S>Именно поэтому я и предлагал сделать String.Replace
другое дело, что String.Replace — криво, надо точечную замену сделать, только в начале документа.
Здравствуйте, dmitritch, Вы писали:
D>Кстати, вот еще вопрос всплыл. Как сделать чтобы опреденное свойство объекта не серилизовалось в xml. Про атрибут XmlIgnore знаю, проблема в том что атрибуты нельзя добавлять во время выполнения. А у меня для части объектов так, а для части хотелось бы по другому.
Есть несколько способов.
Можно использовать дополнительное булево свойство с окончанием *Specified.
Можно использовать дополнительный булев метод с приставкой ShouldSerialize*.
Кроме того, можно на свойство навесить атрибут DefaultValue. И свойство не будет сериализоваться, если оно имеет значение по умолчанию.
Здравствуйте, samius, Вы писали:
S>>Именно поэтому я и предлагал сделать String.Replace S>другое дело, что String.Replace — криво, надо точечную замену сделать, только в начале документа.
Сама идея хранить и обрабатывать бинарные данные как string кривая до невозможности (а это именно бинарные данные, раз нам важен вывод в 1251). Всё остальное — следствие.