Xml сериализация в .Net Framework 2.0

ОГЛАВЛЕНИЕ

Xml широко используется в .Net приложениях, и .Net framework предоставляет богатые возможности по работе с Xml. Среди них: поддержка Xml DOM (System.Xml.XmlDocument), последовательное чтение - запись Xml, поддержка xPath и xQuery, поддержка XSLT, богатые возможности DataSet по работе с Xml и, наконец, Xml сериализация. Xml сериализация позволяет представлять Xml в виде иерархии классов, и наоборот, данные классов представлять в виде Xml. Когда стоит использовать Xml сериализацию? Мое мнение таково. Во всех случаях, когда нам заранее известна структура Xml, с которым предстоит работать, следует использовать Xml сериализацию.

Как работает Xml сериализация

При Xml сериализации, сериализуются все открытые поля и свойства класса. Кроме того, открытые свойства должны иметь аксессоры get и set, а сам класс должен иметь конструктор по умолчанию без параметров. Рассмотрим класс:
public class DataClass
{
public DataClass(){}
public string ID = Guid.NewGuid().ToString();
public string Name = "Just Name";
public Decimal Count = 10;
public DateTime Date = DateTime.Now;
}
Его мы будем использовать во всех дальнейших примерах сериализации и десериализации.

Для сериализации нам надо создать экземпляр класса XmlSerializer, предав в качестве параметра конструктора тип сериализуемого класса. Следующий код демонстрирует сериализацию объекта нашего класса DataClass:
DataClass obj = new DataClass();
// создаем сериалайзер

XmlSerializer sr = new XmlSerializer(obj.GetType());
// создаем writer, в который будет происходить сериализация

StringBuilder sb = new StringBuilder();
StringWriter w = new StringWriter(sb, System.Globalization.CultureInfo.InvariantCulture);
// сериализуем

sr.Serialize(w,obj);
// получаем строку Xml

string xml = sb.ToString();
Console.WriteLine(xml);

В результате получаем вот такой Xml:
<?xml version="1.0" encoding="utf-8"?>
<DataClass xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ID>34332413-e70f-44f7-b35c-b34c47812dbc</ID>
<Name>Just Name</Name>
<Count>10</Count>
<Date>2006-10-30T12:35:20.3110319+03:00</Date>
</DataClass>

Для того, чтобы получить из этого Xml экземпляр класса DataClass (десериализовать), служит следующий код:
// создаем reader

StringReader reader = new StringReader(xml);
// создаем XmlSerializer

XmlSerializer dsr = new XmlSerializer(typeof(DataClass));
// десериализуем

DataClass clone = (DataClass)dsr.Deserialize(reader);
Управлять, тем как свойства и поля объекта отображаются на элементы Xml, можно при помощи атрибутов, которые содержатся в пространстве имен System.Xml.Serialization. Допустим, мы хотим, чтобы в результирующем Xml корневой элемент назывался <Data>, поля “ID”, “Name” сериализовались Xml атрибутами, поле “Count” соответствовало Xml элементу <Reserved>, а поле “Date”, вообще не попадало в результирующий Xml. Для этого расставим соответствующие атрибуты:
    [XmlRoot("Data")] // изменим имя корневого элемента

public class DataClass
{
public DataClass(){}

[XmlAttribute] // сериализуем в xml атрибут

public string ID = Guid.NewGuid().ToString();

[XmlAttribute] // сериализуем в xml атрибут

public string Name = "Just Name";

[XmlElement("Reserved")] // изменим имя xml элемента

public Decimal Count = 10;

[XmlIgnore] // не будет сериализоваться

public DateTime Date = DateTime.Now;
}
Результирующий Xml теперь выглядит так:
<?xml version="1.0" encoding="utf-8"?>
<Data xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
ID="cc340d5e-4c80-4fe5-9c3d-e49f64e26b22" Name="Just Name">
<Reserved>10</Reserved>
</Data>
Как видно из представленного кода, использовать Xml сериализацию не сложно. Но все же попробуем облегчить себе жизнь. Для этого вынесем код, ответственный за сериализацию в отдельный класс утилиту:
public class XmlUtility
{
/// <summary>

/// Сериализует объект в строку XML

/// </summary>

public static string Obj2XmlStr(object obj, string nameSpace)
{
if (obj == null)
return string.Empty;
XmlSerializer sr = new XmlSerializer(type);
StringBuilder sb = new StringBuilder();
StringWriter w = new StringWriter(sb, System.Globalization.CultureInfo.InvariantCulture);
sr.Serialize(
w,
obj,
new XmlSerializerNamespaces(
new XmlQualifiedName[]
{
new XmlQualifiedName("", nameSpace)
}
));
return sb.ToString();
}

/// <summary>

/// Сериализует объект в строку XML

/// </summary>

public static string Obj2XmlStr(object obj)
{
if (obj == null) return string.Empty;
XmlSerializer sr = new XmlSerializer(obj.GetType());
StringBuilder sb = new StringBuilder();
StringWriter w = new StringWriter(sb, System.Globalization.CultureInfo.InvariantCulture);
sr.Serialize(
w,
obj,
new XmlSerializerNamespaces( new XmlQualifiedName[]
{ new XmlQualifiedName(string.Empty) } ) );
return sb.ToString();
}

/// <summary>

/// Десериализует строку XML в объект заданного типа

/// </summary>

/// <param name="xml"></param>

/// <param name="type"></param>

/// <returns></returns>

public static T XmlStr2Obj<T>(string xml)
{
if (xml == null) return default(T);
if (xml == string.Empty) return (T)Activator.CreateInstance(typeof(T));

StringReader reader = new StringReader(xml);
XmlSerializer sr = new XmlSerializer(typeof(T));//SerializerCache.GetSerializer(type);

return (T)sr.Deserialize(reader);
}
}
Назначение метода Obj2XmlStr(object obj, string nameSpace) я объясню несколько позже. Теперь наш код для сериализации и десериализации объекта сократился в несколько раз:
DataClass obj = new DataClass();
string xml = XmlUtility.Obj2XmlStr(obj);
Console.WriteLine(xml);
DataClass clone = XmlUtility.XmlStr2Obj<DataClass>(xml);

Полный код класса XmlUtility вы найдете в исходном коде, прилагаемом к статье.