1. Giriş
XML (eXtensible Markup Language) — genişlənən markup dili, mürəkkəb strukturlu məlumatların saxlanması və mübadiləsi üçün populyar formatdır. JSON-dan fərqli olaraq XML qısa deyil, amma hələ də bank sektorunda, dövlət xidmətləri arasında məlumat mübadiləsində, sənədlərdə və 1C, SAP, Oracle və s. ilə inteqrasiyalarda aktiv istifadə olunur. Windows və .NET-də bəzi məlumatlar (məsələn, konfiglər) hələ də XML formatında saxlanılır.
Vizual olaraq XML HTML-ə oxşayır, amma <body> və <div> kimi sabit tag dəstinə malik deyil — elementlərin strukturunu sən özün təyin edirsən. Məsələn:
<Person>
<FirstName>İvan</FirstName>
<LastName>Petrov</LastName>
<Age>30</Age>
</Person>
XML əsasları və C# obyektlərinə uyğunluq
JSON-dan fərqli olaraq, XML-də massivlər və boolean üçün xüsusi tiplər yoxdur — hər şey elementlər və attributlar vasitəsilə təmsil olunur. Siyahı strukturları eyni adda təkrarlanan elementlər kimi həyata keçirilir.
C#-da XML ilə işləmək üçün XmlSerializer vasitəsilə serializasiya/deserializasiya mexanizmi istifadə olunur.
Serializasiya — C# obyektinin XML sətrinə çevrilməsidir. Deserializasiya — əks proses: XML-dən C# obyektinin alınması.
Bu, siniflərin müəyyən tələblərə uyğun olduğu halda “standart olaraq” işləyir — aşağıda bunları nəzərdən keçirəcəyik.
Niyə XmlSerializer istifadə etməli?
XmlSerializer — .NET-in standart alətidir (ad məkanı System.Xml.Serialization) obyektləri XML-ə və əksinə çevirmək üçün. O, sadədir, type-safe-dir və məlumatların import/eksportu, konfiqurasiyalar, sistemlərarası mübadilə və dövlət xidmətləri ilə inteqrasiyalar üçün uyğundur.
2. Nümunə: obyektin serializasiyası
Tutaq ki, istifadəçi modelimiz var:
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
Obyekti XML-ə serializasiya edək:
using System.Xml.Serialization;
User user = new User { FirstName = "İvan", LastName = "Petrov", Age = 30 };
// Serializasiya üçün tip lazımdır
XmlSerializer serializer = new XmlSerializer(typeof(User));
// XML-i fayla yazırıq
using FileStream fs = new FileStream("user.xml", FileMode.Create);
serializer.Serialize(fs, user);
Nə baş verir?
- User sinifinin obyektini yaradırıq.
- User tipi üçün XmlSerializer nümunəsini yaradırıq.
- FileStream vasitəsilə faylı açırıq.
- Serialize() metodunu çağırırıq, o obyektin XML-ə çevrilib fayla yazılmasını həyata keçirir.
Faylın məzmunu — user.xml:
<?xml version="1.0"?>
<User xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<FirstName>İvan</FirstName>
<LastName>Petrov</LastName>
<Age>30</Age>
</User>
Bax, necə sadədir — minimum kodla hazır XML əldə etdik.
3. Deserializasiya: XML-i yenidən obyektə oxumaq
Yaradılmış XML-i oxuyub C# obyektini bərpa edək:
// XML faylını açırıq
using FileStream fs = new FileStream("user.xml", FileMode.Open);
User? loadedUser = serializer.Deserialize(fs) as User;
Console.WriteLine($"{loadedUser?.FirstName} {loadedUser?.LastName}, yaş: {loadedUser?.Age}");
Deserialize() metodu object qaytarır, ona görə User-a cast edirik (via as). Fayl korrektdirsə və modelə uyğundursa — obyekt tam bərpa olunur.
4. Serializasiyanın necə işlədiyi: tipik xüsusiyyətlər
XML-ə serializasiya üçün qaydalara riayət etmək lazımdır:
• Serializasiya ediləcək sinifin public parametrsiz konstruktoru olmalıdır (public və parametrsiz).
• Serializasiya olunan property-lər — public olmalıdır: həm getter, həm də setter tələb olunur. Private üzvlər nəzərə alınmır.
• Yalnız oxunan property-lər, həmçinin static və abstract üzvlər işləmir.
Qaydalar pozulsa, InvalidOperationException ala bilərsən, mesaj adətən belə olur: "XmlSerializer cannot serialize this type".
5. Kolleksiyaların serializasiyası: massivlər və siyahılar
Bir neçə istifadəçini serializasiya etmək lazımdırsa — obalayan (wrapper) sinifdən istifadə edirik:
public class UserList
{
public List<User> Users { get; set; } = new List<User>();
}
Kolleksiyanı yaradaq və serializasiya edək:
UserList users = new UserList
{
Users = new List<User>
{
new User { FirstName = "İvan", LastName = "Petrov", Age = 30 },
new User { FirstName = "Mariya", LastName = "İvanova", Age = 25 }
}
};
XmlSerializer serializer = new XmlSerializer(typeof(UserList));
using FileStream fs = new FileStream("users.xml", FileMode.Create);
serializer.Serialize(fs, users);
Alınan XML:
<?xml version="1.0"?>
<UserList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Users>
<User>
<FirstName>İvan</FirstName>
<LastName>Petrov</LastName>
<Age>30</Age>
</User>
<User>
<FirstName>Mariya</FirstName>
<LastName>İvanova</LastName>
<Age>25</Age>
</User>
</Users>
</UserList>
Sadəcə List<User> serializasiya etmək mümkündür, amma kök element adətən ArrayOfUser olacaq — bu isə inteqrasiyalar üçün həmişə uyğun olmaya bilər.
6. Serializasiyanı idarə etmək üçün atributlar
Atributlar vasitəsilə XML formatını idarə etmək olar: elementləri yenidən adlandırmaq, attribut kimi serializasiya etmək, sahələri ignor etmək və s. Faydalı atributlar: [XmlElement], [XmlAttribute], [XmlArray], [XmlIgnore].
Attribut kimi serializasiya
Ad və soyadı attribut kimi, yaş isə element kimi yazaq:
public class User
{
[XmlAttribute]
public string FirstName { get; set; }
[XmlAttribute]
public string LastName { get; set; }
[XmlElement]
public int Age { get; set; }
}
Nəticə:
<User FirstName="İvan" LastName="Petrov">
<Age>30</Age>
</User>
Element adlarını idarə etmək
Tag-ları oxunaqlı adlarla əvəz edək:
public class User
{
[XmlElement("Ad")]
public string FirstName { get; set; }
[XmlElement("Soyad")]
public string LastName { get; set; }
[XmlElement("Yaş")]
public int Age { get; set; }
}
Alınan XML:
<User>
<Ad>İvan</Ad>
<Soyad>Petrov</Soyad>
<Yaş>30</Yaş>
</User>
Property-ləri ignor etmək
Əgər property serializasiya olunmamalıdırsa — onu [XmlIgnore] ilə işarə et:
public class User
{
public string FirstName { get; set; }
[XmlIgnore]
public string InternalCode { get; set; }
}
7. İerarxiya və iç-içə obyektlərin serializasiyası
İç-içə siniflər asanlıqla iç-içə XML elementlərinə çevrilir:
public class Address
{
public string City { get; set; }
public string Street { get; set; }
}
public class User
{
public string FirstName { get; set; }
public Address Address { get; set; }
}
var user = new User
{
FirstName = "Anna",
Address = new Address { City = "Neonqrad", Street = "Vyazovaya" }
};
XmlSerializer serializer = new XmlSerializer(typeof(User));
using var fs = new FileStream("user_with_address.xml", FileMode.Create);
serializer.Serialize(fs, user);
XML:
<User>
<FirstName>Anna</FirstName>
<Address>
<City>Neonqrad</City>
<Street>Vyazovaya</Street>
</Address>
</User>
8. Sətirə serializasiya / sətirdən deserializasiya (fayl olmadan)
Sətirə serializasiya
using System.Text;
var serializer = new XmlSerializer(typeof(User));
using var stringWriter = new StringWriter();
serializer.Serialize(stringWriter, user);
string xml = stringWriter.ToString();
Console.WriteLine(xml);
Sətirdən deserializasiya
var xml = "<User><FirstName>Anna</FirstName></User>";
using var stringReader = new StringReader(xml);
User user = (User)serializer.Deserialize(stringReader);
Console.WriteLine(user.FirstName);
9. Nümunə: tətbiq məlumatlarının eksportu və importu
İstifadəçilər siyahısını XML faylına eksport/import nümunəsi:
public static void ExportUsers(UserList users, string path)
{
var serializer = new XmlSerializer(typeof(UserList));
using var fs = new FileStream(path, FileMode.Create);
serializer.Serialize(fs, users);
}
public static UserList ImportUsers(string path)
{
var serializer = new XmlSerializer(typeof(UserList));
using var fs = new FileStream(path, FileMode.Open);
return (UserList)serializer.Deserialize(fs);
}
Tətbiq sahələri: ehtiyat nüsxə çıxarma, digər servislərlə mübadilə, inteqrasiyalar. İş müsahibələrində XmlSerializer ilə bağlı suallar düşündüyündən daha çox rast gəlinə bilər — xüsusən dövlət xidmətləri və banklarla işləyən şirkətlərdə.
10. Tipik səhvlər və iş zamanı xüsusiyyətlər
Əgər sahə public deyilsə, o serializasiya olunmayacaq.
Yalnız oxunan property-lər ignor edilir.
İnterfeys tipli və ya abstract tipli property-ləri serializer dəstəkləməyə bilər.
Tip DateTime XSD formatında serializasiya olunur (bax: sənəd).
Massivlər və List<T> kimi kolleksiyalar proqnozlaşdırıla bilən şəkildə işləyir, lakin ObservableCollection<T> ilə üçüncü tərəf sistemlərdə sürprizlər ola bilər.
Kodlaşdırma nüansları: StreamWriter vasitəsilə explicit kodlaşdırma göstərilmədən yazılsa nəticə UTF-16 ola bilər; uyğunluq üçün daha çox UTF-8 gözlənilir — kodlaşdırmanı açıq göstər.
GO TO FULL VERSION