Вопрос про серилизацию объектов в Xml.
От: dmitritch  
Дата: 17.03.14 07:39
Оценка:
Был у меня метод серилизующий объекты моего типа в 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? Спасибо большое заранее.
Re: Вопрос про серилизацию объектов в Xml.
От: baranovda Российская Империя  
Дата: 17.03.14 07:49
Оценка: +2
Здравствуйте, dmitritch, Вы писали:

D>
D>        public string serializeToString(MyObject item)
D>


Все как бы круто, только string — это по определению набор двухбайтовых символов в UNICODE, поэтому понятие "кодировка" для System.String в данном контексте бессмысленно. "Кодировка" приобретает смысл если XML сериализуется в какой-то внешний поток (файл, поток в памяти, LOB базы данных и так далее).
Re[2]: Вопрос про серилизацию объектов в Xml.
От: dmitritch  
Дата: 17.03.14 07:58
Оценка:
Здравствуйте, baranovda, Вы писали:

B>Здравствуйте, dmitritch, Вы писали:


D>>
D>>        public string serializeToString(MyObject item)
D>>


B>Все как бы круто, только string — это по определению набор двухбайтовых символов в UNICODE, поэтому понятие "кодировка" для System.String в данном контексте бессмысленно. "Кодировка" приобретает смысл если XML сериализуется в какой-то внешний поток (файл, поток в памяти, LOB базы данных и так далее).


Спасибо, вы правы. Просто потом я пергоняю эту строку в массив байтов и гружу в базу, и мне надо чтобы в заголовке xml была явно указана кодировка cp1251, а не utf16 как у меня получалось в первом варианте.
Re[3]: Вопрос про серилизацию объектов в Xml.
От: baranovda Российская Империя  
Дата: 17.03.14 08:07
Оценка:
Здравствуйте, dmitritch, Вы писали:

D>Спасибо, вы правы. Просто потом я пергоняю эту строку в массив байтов и гружу в базу, и мне надо чтобы в заголовке xml была явно указана кодировка cp1251, а не utf16 как у меня получалось в первом варианте.


Понятно. Если нужен заголовок, а XML нужен именно как поток байтов в однобайтовой кодировке, то думаю, что красивей всего будет выполнить преобразование XML при помощи самой простой XSL cразу в какой-нибудь поток (MemoryStream или типа того):

<xsl:stylesheet ...>
<xsl:output method="xml" encoding="windows-1251">
<xsl:template match="/">
<xsl:copy-of select="/" />
</xsl:template>
</xsl:stylesheet>

Кстати что за база? Современные СУБД сейчас почти все имеют типы данных для работы с XML и умеют его хранить не в блобах, а в структурированном виде.
Re[3]: Вопрос про серилизацию объектов в Xml.
От: samius Япония http://sams-tricks.blogspot.com
Дата: 17.03.14 08:08
Оценка:
Здравствуйте, dmitritch, Вы писали:

D>Спасибо, вы правы. Просто потом я пергоняю эту строку в массив байтов и гружу в базу, и мне надо чтобы в заголовке xml была явно указана кодировка cp1251, а не utf16 как у меня получалось в первом варианте.

сделайте замену String.Replace ))
Re[4]: Вопрос про серилизацию объектов в Xml.
От: dmitritch  
Дата: 17.03.14 09:04
Оценка:
Здравствуйте, 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 и умеют его хранить не в блобах, а в структурированном виде.



Oracle. Посмотрю насчет хранения xml.
Re[3]: Вопрос про серилизацию объектов в Xml.
От: Sinix  
Дата: 17.03.14 09:15
Оценка:
Здравствуйте, dmitritch, Вы писали:

D>Спасибо, вы правы. Просто потом я пергоняю эту строку в массив байтов и гружу в базу, и мне надо чтобы в заголовке xml была явно указана кодировка cp1251, а не utf16 как у меня получалось в первом варианте.

Лучше сразу перегонять как массив байтов или поток.

Кодировка в заголовке должна соответствовать кодировке тела. Вы же сначала пишете в 1251, потом читаете из этого же потока как UTF-8 (проверить легко, см исходники).
Re[4]: Вопрос про серилизацию объектов в Xml.
От: dmitritch  
Дата: 17.03.14 09:37
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Здравствуйте, dmitritch, Вы писали:


D>>Спасибо, вы правы. Просто потом я пергоняю эту строку в массив байтов и гружу в базу, и мне надо чтобы в заголовке xml была явно указана кодировка cp1251, а не utf16 как у меня получалось в первом варианте.

S>Лучше сразу перегонять как массив байтов или поток.

S>Кодировка в заголовке должна соответствовать кодировке тела. Вы же сначала пишете в 1251, потом читаете из этого же потока как UTF-8 (проверить легко, см исходники).



Да, все заметил, действительно нужно сразу поток загонять в байты а не строку, потому что в строке кодировка получается utf 16.
Re[5]: Вопрос про серилизацию объектов в Xml.
От: baranovda Российская Империя  
Дата: 17.03.14 09:41
Оценка:
Здравствуйте, dmitritch, Вы писали:

D>Oracle. Посмотрю насчет хранения xml.


В Oracle для работы с XML есть тип XMLType, умеет принимать в конструкторе well-formed XML. Но у него есть несколько неприятных багов: а) в 10g длина текста в текстовом узле не может превышать 32 кб (возможно, в 11 уже исправлено) б) он всегда преобразует внутренние строки к кодировке базы данных. Т.е. если база создана в CL8MSWIN1251, а ему будет передана строка NVARCHAR2, то он преобразует многобайтовую строку в однобайтовую и это приведет к утере данных. Но зато заголовок <?xml version= encoding= ?> он добавит сам, т.е. на клиенте никаких преобразований с кодировками делать не надо, надо лишь передать String через JDBC/ODBC/OLEDB/ADO.NET драйвер.
Re[4]: Вопрос про серилизацию объектов в Xml.
От: Mr.Delphist  
Дата: 17.03.14 09:59
Оценка:
Здравствуйте, samius, Вы писали:

S>Здравствуйте, dmitritch, Вы писали:


D>>Спасибо, вы правы. Просто потом я пергоняю эту строку в массив байтов и гружу в базу, и мне надо чтобы в заголовке xml была явно указана кодировка cp1251, а не utf16 как у меня получалось в первом варианте.

S>сделайте замену String.Replace ))

За такое — пожизненный эцих с гвоздями. Уж сколько раз спотыкались об эти расхождения заголовка и реального формата.
Re[5]: Вопрос про серилизацию объектов в Xml.
От: samius Япония http://sams-tricks.blogspot.com
Дата: 17.03.14 10:08
Оценка:
Здравствуйте, Mr.Delphist, Вы писали:

MD>Здравствуйте, samius, Вы писали:



D>>>Спасибо, вы правы. Просто потом я пергоняю эту строку в массив байтов и гружу в базу, и мне надо чтобы в заголовке xml была явно указана кодировка cp1251, а не utf16 как у меня получалось в первом варианте.

S>>сделайте замену String.Replace ))

MD>За такое — пожизненный эцих с гвоздями. Уж сколько раз спотыкались об эти расхождения заголовка и реального формата.

Если использовать промежуточную дотнет строку, то разницу в форматах заметить будет проблематично.
А по делу — оно, конечно, сохранять в Stream и гнать в базу байты без использования промежуточной строки. Тут я согласен.
Re[6]: Вопрос про серилизацию объектов в Xml.
От: Sinix  
Дата: 17.03.14 11:28
Оценка:
Здравствуйте, samius, Вы писали:

S>Если использовать промежуточную дотнет строку, то разницу в форматах заметить будет проблематично.


Да ну
        public class MyObject
        {
            public string A { get; set; }
        }
        static void Main(string[] args)
        {
            MyObject s = new MyObject { A = "Проверка" };
            string s2 = serializeToString(s);
            Console.WriteLine(s2); // <MyObject xmlns:....><A>��������</A></MyObject>
        }
Re[4]: Вопрос про серилизацию объектов в Xml.
От: dmitritch  
Дата: 17.03.14 11:57
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Здравствуйте, dmitritch, Вы писали:


D>>Спасибо, вы правы. Просто потом я пергоняю эту строку в массив байтов и гружу в базу, и мне надо чтобы в заголовке xml была явно указана кодировка cp1251, а не utf16 как у меня получалось в первом варианте.

S>Лучше сразу перегонять как массив байтов или поток.

S>Кодировка в заголовке должна соответствовать кодировке тела. Вы же сначала пишете в 1251, потом читаете из этого же потока как UTF-8 (проверить легко, см исходники).


Кстати, вот еще вопрос всплыл. Как сделать чтобы опреденное свойство объекта не серилизовалось в xml. Про атрибут XmlIgnore знаю, проблема в том что атрибуты нельзя добавлять во время выполнения. А у меня для части объектов так, а для части хотелось бы по другому.
Re[5]: Вопрос про серилизацию объектов в Xml.
От: Sinix  
Дата: 17.03.14 12:05
Оценка:
Здравствуйте, dmitritch, Вы писали:

D>Кстати, вот еще вопрос всплыл. Как сделать чтобы опреденное свойство объекта не серилизовалось в xml. Про атрибут XmlIgnore знаю, проблема в том что атрибуты нельзя добавлять во время выполнения. А у меня для части объектов так, а для части хотелось бы по другому.


1. XmlAttributes (см пример вот тут)
2. IXmlSerializable (если нужен полный контроль)
Re[7]: Вопрос про серилизацию объектов в Xml.
От: samius Япония http://sams-tricks.blogspot.com
Дата: 17.03.14 12:36
Оценка:
Здравствуйте, 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, то все было бы как надо
Re[8]: Вопрос про серилизацию объектов в Xml.
От: Sinix  
Дата: 17.03.14 12:58
Оценка:
Здравствуйте, samius, Вы писали:

S>Если бы прочитали тоже с 1251, то все было бы как надо


По-моему строка xml в utf16 с заголовком "<?xml version="1.0" encoding="windows-1251"?>" вообще не похожа на "как надо"
Re[9]: Вопрос про серилизацию объектов в Xml.
От: samius Япония http://sams-tricks.blogspot.com
Дата: 17.03.14 13:00
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Здравствуйте, samius, Вы писали:


S>>Если бы прочитали тоже с 1251, то все было бы как надо


S>По-моему строка xml в utf16 с заголовком "<?xml version="1.0" encoding="windows-1251"?>" вообще не похожа на "как надо"

Именно поэтому я и предлагал сделать String.Replace
Re[10]: Вопрос про серилизацию объектов в Xml.
От: samius Япония http://sams-tricks.blogspot.com
Дата: 17.03.14 13:02
Оценка:
Здравствуйте, samius, Вы писали:

S>Именно поэтому я и предлагал сделать String.Replace

другое дело, что String.Replace — криво, надо точечную замену сделать, только в начале документа.
Re[5]: Вопрос про серилизацию объектов в Xml.
От: koodeer  
Дата: 17.03.14 13:10
Оценка:
Здравствуйте, dmitritch, Вы писали:

D>Кстати, вот еще вопрос всплыл. Как сделать чтобы опреденное свойство объекта не серилизовалось в xml. Про атрибут XmlIgnore знаю, проблема в том что атрибуты нельзя добавлять во время выполнения. А у меня для части объектов так, а для части хотелось бы по другому.


Есть несколько способов.

Можно использовать дополнительное булево свойство с окончанием *Specified.
Можно использовать дополнительный булев метод с приставкой ShouldSerialize*.

Кроме того, можно на свойство навесить атрибут DefaultValue. И свойство не будет сериализоваться, если оно имеет значение по умолчанию.
Re[11]: Вопрос про серилизацию объектов в Xml.
От: Sinix  
Дата: 17.03.14 13:51
Оценка: +1
Здравствуйте, samius, Вы писали:

S>>Именно поэтому я и предлагал сделать String.Replace

S>другое дело, что String.Replace — криво, надо точечную замену сделать, только в начале документа.

Сама идея хранить и обрабатывать бинарные данные как string кривая до невозможности (а это именно бинарные данные, раз нам важен вывод в 1251). Всё остальное — следствие.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.