1. Giriş
Artıq bilirsiniz ki, .NET default olaraq public sahələrə və propertielərə əsaslanaraq obyektləri XML-ə serialize və deserialize edə bilir. Amma gözəl, xarici proqramlara/standartlara uyğun XML yaratmaq, ya da XML-ə bəzi daxili detalların daxil olmamasını istəyirsinizsə, incə tənzimləmə lazımdır.
C#-da bunun üçün serializasiya atributları var — sinifləri, propertieləri və ya sahələri işarələmək üçün xüsusi "tag"lar. Bu atributlar sayəsində hər şeyi idarə edə bilirsiniz: hansı sahələr XML-ə düşəcək, hansılar ignore ediləcək, elementin adı nə olacaq, atribut olaraq yazılacaq, mürəkkəb struktur olacaq, hətta elementlərin sırası nə olacaq!
Default serializasiya avtomatik form doldurma kimidir: ad-familiya-ata adı öz yerlərində, qalanı necə gəldi. Atributlarla siz super-kanselyar kimi qərar verirsiniz: hansı sətri haraya yazmaq, nəyi ötürmək, nəyi qırmızıya çəkmək, nəyi sirr bölməsinə keçirmək.
Obyektin və XML-in uyğunlaşdırılması
| Sinif/Property | Atribut | XML-də nəticə |
|---|---|---|
|
Class UserList | |
|
|
|
|
|
id="..." (atribut) |
|
|
|
|
|
|
|
[XmlIgnore] (bax RegisteredAtString) | - |
|
|
|
|
|
|
2. XML serializasiyasının əsas atributlarına baxış
Gəlin .NET istifadəçilərinin nəslər boyu siniflərini bəzədiyi ən populyar atributlara baxaq!
Atribut [XmlElement] — Elementin adı
XML-də elementin adını dəyişir və ya property/field-i XML-element kimi işarələyir.
public class Person
{
[XmlElement("FullName")]
public string Name { get; set; }
}
XML:
<Person>
<FullName>Vasiliy Petrov</FullName>
</Person>
Əgər atribut göstərməsəniz — default olaraq elementin adı property/field-in adı ilə eyni olacaq.
Atribut [XmlAttribute] — XML atribut kimi serializasiya
Property/field-i element əvəzinə XML-atribut kimi serialize etməyə imkan verir.
public class Person
{
[XmlAttribute("id")]
public int Id { get; set; }
}
XML:
<Person id="123"></Person>
Real XML-API-lərdə adlar, tarixlər, flag-lər üçün atributlar tez-tez istifadə olunur.
Atribut [XmlIgnore] — Field/property-ni keçirmək
Paranoid üçün arzu: property-ni tamamilə serializasiya və deserializasiyadan çıxarmaq! Bu atributla işarələnmiş hər şey final XML-ə düşməyəcək.
public class Person
{
[XmlIgnore]
public string InternalNote { get; set; }
}
XML: (InternalNote burada yoxdur və olmayacaq)
Atributlar [XmlArray] və [XmlArrayItem] — kolleksiyalara nəzarət
Array və kolleksiyalar üçün xüsusi atributlar. [XmlArray] xarici wrapper-in adını verir, [XmlArrayItem] isə ayrı elementin adını təyin edir.
public class Person
{
[XmlArray("Phones")]
[XmlArrayItem("Phone")]
public string[] PhoneNumbers { get; set; }
}
XML:
<Person>
<Phones>
<Phone>+12951234567</Phone>
<Phone>+12876543210</Phone>
</Phones>
</Person>
Atribut [XmlRoot] — Root elementin adı
Sinifi işarələyib XML-də root elementin adını dəyişməyə imkan verir.
[XmlRoot("User")]
public class Person
{
public string Name { get; set; }
}
XML:
<User>
<Name>Anna</Name>
</User>
Atribut [XmlText] — Elementin mətn məzmunu kimi serializasiya
Bəzən (və ya spesifikasiya tələb edirsə) property-nin dəyəri elementin içində sadəcə mətn kimi olmalıdır, nested element və ya atribut kimi yox.
public class Note
{
[XmlText]
public string Content { get; set; }
}
XML:
<Note>Pozvoni babushke!</Note>
Atributlar [XmlNamespaceDeclarations], [XmlElement(Type = ...)]
Daha avanqard ssenarilər (məsələn, namespace-lərlə serializasiya, inheritance dəstəyi və s.) üçün spesifik atributlar da var. Tam siyahı üçün mütləq rəsmi sənədlərə baxın.
3. Praktika: real nümunədə serializasiyanı yaxşılaşdırmaq
Gəlin addım-addım tədris tətbiqimizi "XML-serializasiya premium" səviyyəsinə gətirək ki, ən ciddi XML-inspektoru da razı qalsın.
Atributlar olmadan baza sinif
Tutaq ki, istifadəçi üçün belə bir sinifimiz var:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string[] Emails { get; set; }
public DateTime RegisteredAt { get; set; }
public string Password { get; set; }
}
Default serializasiya təxminən belə XML verəcək (tarixi öz formatında yazacaq):
<User>
<Id>42</Id>
<Name>Ivan Ivanov</Name>
<Emails>
<string>user@mail.com</string>
<string>admin@site.org</string>
</Emails>
<RegisteredAt>2024-07-01T00:00:00</RegisteredAt>
<Password>qwerty</Password>
</User>
Nə problemdir:
- Şifrə ümumiyyətlə serializasiya olunmasın.
- Tarixi atribut olaraq və insan üçün oxunaqlı formatda istəyirik.
- Emails-ləri gözəl formada istəyirik.
- Root elementi <Person> olsun istəyirik.
Atributlarla tənzimləmə əlavə edirik
[XmlRoot("Person")]
public class User
{
[XmlAttribute("id")]
public int Id { get; set; }
[XmlElement("FullName")]
public string Name { get; set; }
[XmlArray("EMails")]
[XmlArrayItem("Email")]
public string[] Emails { get; set; }
[XmlAttribute("registered")]
public string RegisteredAtString
{
get => RegisteredAt.ToString("yyyy-MM-dd");
set => RegisteredAt = DateTime.Parse(value);
}
[XmlIgnore]
public string Password { get; set; }
[XmlIgnore]
public DateTime RegisteredAt { get; set; }
}
İncə məqamların açıqlaması:
- Tarixi atribut kimi serializasiya etmək üçün [XmlAttribute("registered")] istifadə edirik.
- Birbaşa DateTime-ı deyil, onun string təmsilini serializasiya etmək üçün ayrıca RegisteredAtString property əlavə edirik, real sahəni isə [XmlIgnore] ilə gizlədirik.
- Şifrəni [XmlIgnore] ilə gizlədirik.
- Email massivini belə tənzimləyirik: xarici tag <EMails>, hər email üçün isə <Email>.
Nəticə:
<Person id="42" registered="2024-07-01">
<FullName>Ivan Ivanov</FullName>
<EMails>
<Email>user@mail.com</Email>
<Email>admin@site.org</Email>
</EMails>
</Person>
4. Nested obyektlərlə işləmək
XML nested obyektlər olduqda ən yaxşısını göstərir (məsələn, istifadəçi və onun ünvanları).
public class Address
{
[XmlAttribute]
public string City { get; set; }
[XmlText]
public string Details { get; set; }
}
public class User
{
// ...digər propertielər, yuxarıya baxın...
public Address[] Addresses { get; set; }
}
Və ünvan massivinə tənzimləmə əlavə edək:
[XmlArray("UserAddresses")]
[XmlArrayItem("Address")]
public Address[] Addresses { get; set; }
Onda XML belə olacaq:
<Person id="42" registered="2024-07-01">
<FullName>Ivan Ivanov</FullName>
<EMails>
<Email>user@mail.com</Email>
</EMails>
<UserAddresses>
<Address City="Neon city">ul. Zamkovaya, d.1</Address>
<Address City="North Cave">ul. Kraynaya d.12</Address>
</UserAddresses>
</Person>
Göründüyü kimi hər <Address>-in City atributu var, ünvanın özü isə elementin içində mətndir.
5. Tez-tez rast gəlinən səhvlər və nüanslar
Əgər mürəkkəb bir obyekti serialize edirsinizsə və gözlədiyiniz dəyişiklikləri XML-də görmürsünüzsə — çox güman ki, atributu düzgün göstərməmisiniz. Bəzən propertielər/sahələr markalanmamış qalır, onda .NET default davranışı seçir.
Bir başqa tələyə diqqət: kolleksiya adı. Əgər kolleksiya (məsələn, string massivi) həm [XmlArray], həm [XmlArrayItem] ilə işarələnməyibsə, elementlər string tagı ilə yazılacaq (ilk nümunədə görüldüyü kimi). Bunun olmaması üçün həmişə tag adlarını açıq şəkildə verin.
"Getter-only" tipli propertielərlə ehtiyatlı olun — onlar default olaraq deserializasiya olunmur. Public set qoymağa çalışın.
Bəzi tiplər (məsələn, dictionary-lər və ya interface-lər) standart XmlSerializer ilə serialize olunmur və ya əlavə işlənmə tələb edir.
GO TO FULL VERSION