Страница 3 из 5 Сериализация массивов и коллекций
Рассмотрим некоторые особенности сериализации массивов и коллекций. Для этого добавим в объявление нашего сериализуемого класса поле в виде массива строк: [XmlRoot("Data", Namespace=DataClass.XmlNamespace )] public class DataClass { ... public string[] Lines = new string[] { "Line one", "Line two", "Line three" }; }
После сериализации мы получим следующий Xml <?xml version="1.0" encoding="utf-8"?> <Data ID="cafaafbf-fa51-47d5-a921-0ffeb8a7e345" Name="Just Name" xmlns="urn:MyDataClass"> <Reserved>10</Reserved> <Lines> <string>Line one</string> <string>Line two</string> <string>Line three</string> </Lines> </Data>
По умолчанию, массив (коллекция) сериализуется в xml элемент с именем поля или свойства, в который вложены элементы, входящие в массив. Возможно, это не совсем тот Xml который вы хотели бы увидеть. Управлять сериализацией массива помогают атрибуты XmlArray, XmlArrayItem, и XmlElement. Давайте рассмотрим эти возможности подробнее. Меня, например, не устраивает то, что элементы массива называются <string>. Мне нужно, чтобы элементы назывались <Line>. Достигается это при помощи атрибута XmlArrayItem над полем Lines. Если же нам надо изменить название элемента <Lines>, то для этого используем атрибут XmlArray: [XmlArray("Specification")] [XmlArrayItem("Line")] public string[] Lines = new string[] { "Line one", "Line two", "Line three" };
Результирующий Xml изменился: <?xml version="1.0" encoding="utf-8"?> <Data ID="64a2c310-fa58-4a28-9cb2-7652625b28fc" Name="Just Name" xmlns="urn:MyDataClass"> <Reserved>10</Reserved> <Specification> <Line>Line one</Line> <Line>Line two</Line> <Line>Line three</Line> </Specification> </Data>
Ну, и, наконец, часто бывают ситуации, когда мы хотели бы вообще избавиться от элемента <Specification> и получить вот такой xml: <?xml version="1.0" encoding="utf-8"?> <Data ID="58f7271e-d6b2-4c7f-b3f3-334d8f087f09" Name="Just Name" xmlns="urn:MyDataClass"> <Reserved>10</Reserved> <Line>Line one</Line> <Line>Line two</Line> <Line>Line three</Line> </Data>
Делается это достаточно просто. Вместо атрибутов XmlArray и XmlArrayItem следует явно задать атрибут XmlElement над полем или свойством типа массива или коллекции. Для получения приведенного выше Xml, используем следующий код: [XmlElement("Line")] public string[] Lines = new string[] { "Line one", "Line two", "Line three" };
Подобно массивам сериализуются коллекции. Например мы можем добавить в объявление DataClass поле типа ArrayList и заполнить его различными значениями: public class DataClass { ... public ArrayList List = new ArrayList(); }
DataClass obj = new DataClass(); obj.List.Add(new DataClass()); obj.List.Add("This is a string"); string xml = XmlUtility.Obj2XmlStr(obj, DataClass.XmlNamespace); Console.WriteLine(xml);
Сериалайзер справился с поставленной задачей и выдал вот такой xml: <?xml version="1.0" encoding="utf-8"?> <Data ID="b1d70646-0985-424a-b87b-1e910173c9e5" Name="Just Name" xmlns="urn:MyDataClass"> <Reserved>10</Reserved> <Line>Line one</Line> <Line>Line two</Line> <Line>Line three</Line> <List> <anyType d3p1:type="DataClass" ID="0a57f292-7a0e-479d-93e2-6c42fa019025" Name="Just Name" xmlns:d3p1="https://www.w3.org/2001/XMLSchema-instance"> <Reserved>10</Reserved> <Line>Line one</Line> <Line>Line two</Line> <Line>Line three</Line> <List /> </anyType> <anyType xmlns:q1="https://www.w3.org/2001/XMLSchema" d3p1:type="q1:string" xmlns:d3p1="https://www.w3.org/2001/XMLSchema-instance">This is a string</anyType> </List> </Data>
Элементы списка сериализуются в xml элементы <anyType>, в которые добавляется дополнительная информация о типе каждого элемента. Однако, подобная сериализация, это не самая лучшая идея, поверьте. Особенно если данный Xml предназначен для обмена данными с другой системой. Дело в том, что в нашем случае схема результирующего Xml расширяется в runtime в зависимости от типа элементов, добавляемых в коллекцию. Далеко не все системы смогут правильно обработать такой Xml. По возможности, следует избегать использования не типизированных коллекций. Совсем другое дело - использование Generic коллекций. Модифицируем наш DataClass следующим образом, вместо ArrayList используем List<DataClass>: public class DataClass { ... public List<DataClass> List = new List<DataClass>(); }
Результирующий Xml выглядит теперь вот так: <?xml version="1.0" encoding="utf-8"?> <Data ID="13688ff2-c55f-45d7-8498-750a3e5df1d1" Name="Just Name" xmlns="urn:MyDataClass"> <Reserved>10</Reserved> <Line>Line one</Line> <Line>Line two</Line> <Line>Line three</Line> <List> <DataClass ID="c250a091-4d99-40eb-a870-201f6130579b" Name="Just Name"> <Reserved>10</Reserved> <Line>Line one</Line> <Line>Line two</Line> <Line>Line three</Line> <List /> </DataClass> </List> </Data>
Как мы можем убедиться из xml исчезли элементы <anyType>, потому что тип элементов коллекции известен заранее. |