Xml сериализация в .Net Framework 2.0
Страница 3. Сериализация массивов и коллекций


 

Сериализация массивов и коллекций

Рассмотрим некоторые особенности сериализации массивов и коллекций. Для этого добавим в объявление нашего сериализуемого класса поле в виде массива строк:
 [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();
}

// создаем экземпляр и наполняем коллекцию List различными объектами

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 ArrayList List = new ArrayList();

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>, потому что тип элементов коллекции известен заранее.

 
Следующая статья »