1. Giriş
Bir SOAP‑servis və ya bank API-si sizə nəhəng XML göndərdiyini təsəvvür edin. İçində yüzlərlə bükülmüş element, qeyri‑homogen struktur var və sizdən tələb olunur keçən ayın yalnız bir ödəniş məbləğini tapmaq. Serializasiya yanaşması burada uyğun gəlmir — çox köhnə‑tip və əvvəlcədən haraya baxılacağını bilmirsiniz. XML‑də "böyüdücü" və ağacda sürətlə hərəkət etməyi bacarmaq lazımdır.
Məhz belə hallar üçün .NET‑də uzun illərdir güclü vasitə var — XmlDocument sinfi və ona əlavə olaraq sorğu dili XPath. Bu gün öyrənəcəksiniz:
- XML‑i DOM‑a yükləmək;
- Əllə və XPath ilə lazım olan elementlərə hərəkət etmək və tapmaq;
- XML sənədinin məzmununu modifikasiya etmək;
- Element və atribut əlavə etmək, silmək və dəyişmək;
- Çətin seçkilər üçün XPath istifadə etmək.
2. XmlDocument nədir?
XmlDocument — System.Xml namespace‑indən olan sinifdir. Bu, Document Object Model‑in (DOM) — bütün XML faylını yaddaşda obyektlər ağacı kimi təqdim edən realizasiyasıdır.
Bir az nəzəriyyə və analoqlar
Əgər XmlSerializer LEGO konstruktora oxşayırsa — obyektinizi kubiklərə çevirirsiniz və geri, onda XmlDocument həqiqi bir ağacla işləməyə bənzəyir: kök, budaqlar (elementlər), yarpaqlar (text node‑lar) var və siz bu ağacda gəzə, budaqlar əlavə edə, yarpaqları kəsib başqa yerə köçürə bilərsiniz.
XML sənədinin sadə yüklənməsi
Tutaq ki, bizim belə bir XML‑imiz var:
<users>
<user id="1">
<name>Olga</name>
<age>28</age>
</user>
<user id="2">
<name>Igor</name>
<age>35</age>
</user>
</users>
Bunu yaddaşa yükləyək:
using System.Xml;
string xml = @"
<users>
<user id='1'>
<name>Olga</name>
<age>28</age>
</user>
<user id='2'>
<name>Igor</name>
<age>35</age>
</user>
</users>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml); // veya doc.Load("fayl_yolu.xml");
LoadXml (və ya fayldandırsa Load) çağırdıqdan sonra sənədin məzmununa tam girişiniz olur.
3. DOM‑a naviqasiya
DOM ağacının strukturu
Hər XML sənədi yükləndikdən sonra müxtəlif tiplərdə node‑lardan ibarət bir ağaca çevrilir:
| Node tipi | .NET sinfi | Nümunə |
|---|---|---|
| Document | XmlDocument | |
| Element | XmlElement | |
| Attribute | XmlAttribute | |
| Text | XmlText | Olga, 28 |
| Comment | XmlComment | |
Lazım olan elementlərə müraciət etmək üçün ChildNodes, Attributes, ParentNode və s. kimi property‑lərdən "ağac boyunca gəzərək" istifadə etməlisiniz.
Kök elementi əldə edirik
XmlElement root = doc.DocumentElement;
Console.WriteLine(root.Name); // users
Uşaq elementləri ilə dövr
foreach (XmlNode node in root.ChildNodes)
{
if (node is XmlElement user)
{
// user — <user id="...">...</user>
string id = user.GetAttribute("id");
string name = user["name"].InnerText;
string age = user["age"].InnerText;
Console.WriteLine($"Istifadəçi {id}: {name}, yaş {age}");
}
}
VACIB: user["name"] yalnız birbaşa child olaraq <name> varsa işləyir.
Atributlara və mətinə giriş
var firstUser = root.FirstChild as XmlElement;
string id = firstUser.GetAttribute("id"); // "1"
string name = firstUser["name"].InnerText; // "Olga"
4. XML sənədinin modifikasiyası
Dəyərin dəyişdirilməsi
Tutaq ki, Olga birdən "gəncləşmək" qərarına gəldi:
var olga = root.FirstChild as XmlElement;
olga["age"].InnerText = "22"; // indi <age>22</age>
Yeni istifadəçi əlavə etmək
XmlElement newUser = doc.CreateElement("user");
newUser.SetAttribute("id", "3");
XmlElement name = doc.CreateElement("name");
name.InnerText = "Vasilisa";
XmlElement age = doc.CreateElement("age");
age.InnerText = "19";
newUser.AppendChild(name);
newUser.AppendChild(age);
root.AppendChild(newUser);
Elementi silmək
İkinci istifadəçini ("Igor") silək:
XmlNode userToDelete = root.SelectSingleNode("user[@id='2']");
if (userToDelete != null)
root.RemoveChild(userToDelete);
Dəyişiklikləri saxlamaq
doc.Save("users_updated.xml");
// Və ya doc.OuterXml — XML sətiri almaq üçün
5. XPath — XML-də axtarış və seçmə dili
Əgər DOM ağacı ilə işləmək yorucu olur, çünki şərtə görə element tapmaq lazımdırsa — məsələn, bütün 25‑dən yuxarı istifadəçilər. Bunun üçün XPath var — XML ağacı üzrə naviqasiya dilidir.
XPath-in əsas istifadəsi
XPath sorğularını SelectSingleNode (ilk tapılan node‑u qaytarır) və SelectNodes (node kolleksiyası qaytarır) vasitəsilə icra etmək olar.
Nümunə: id = 1 olan istifadəçini tapmaq
XmlNode user = root.SelectSingleNode("user[@id='1']");
Console.WriteLine(user["name"].InnerText); // Olga
Nümunə: 25‑dən böyük bütün istifadəçiləri tapmaq
XmlNodeList nodes = root.SelectNodes("user[age>25]");
foreach (XmlNode u in nodes)
{
Console.WriteLine(u["name"].InnerText); // Olga və Igor (əgər Igor hələ silinməyibsə)
}
XPath — qısa sintaksis
| XPath ifadəsi | Nə edəcək |
|---|---|
|
root <users> içindəki bütün <user> elementləri |
|
id=3 olan istifadəçi |
|
25‑dən böyük istifadəçilər |
|
Bütün istifadəçilərin bütün <name> elementləri |
|
Son <user> |
|
ilk iki <user> |
Daha çox nümunə və sintaksis: XPath sənədləşməsi.
Başqa bir nümunə: nested elementlərə görə seçmə
Tutaq ki, XML daha mürəkkəbdir:
<library>
<book>
<title>Lord of the Flies</title>
<author>
<firstname>William</firstname>
<lastname>Golding</lastname>
</author>
</book>
<book>
<title>In Search of Lost Time</title>
<author>
<firstname>Marcel</firstname>
<lastname>Proust</lastname>
</author>
</book>
</library>
XmlDocument doc = new XmlDocument();
doc.LoadXml(libraryXml);
XmlNodeList authors = doc.SelectNodes("/library/book/author/lastname");
foreach (XmlNode lastName in authors)
Console.WriteLine(lastName.InnerText);
Nə çap olunacaq:
Golding
Proust
6. XPath: filtrasiya, məntiq, hesablamalar
Məntiqi filtrlər
Yaşı 18 və 30 arasında olan bütün istifadəçilərin adlarını çıxarmaq:
// [age>=18 and age<=30]
XmlNodeList youngUsers = root.SelectNodes("user[age>=18 and age<=30]");
foreach (XmlNode u in youngUsers)
Console.WriteLine(u["name"].InnerText);
Atributlarla işləmək
Atributlar @ ilə seçilir. id‑si "1" ilə başlayan istifadəçiləri tapmaq:
XmlNodeList nodes = root.SelectNodes("user[starts-with(@id, '1')]");
Node sayını saymaq
C#‑da birbaşa SelectNodes metodunda count() funksiyasını istifadə edə bilməzsiniz — o, kolleksiya qaytarır, ədəd yox. Amma belə edə bilərsiniz:
int count = root.SelectNodes("user").Count;
Nested filtrlər
XmlNodeList nodes = doc.SelectNodes("/library/book[author/lastname='Golding']");
7. XPath və namespace‑lər
Əgər XML‑də namespace (xmlns) istifadə olunubsa, iş bir az daha maraqlı olur. Belə hallarda XmlNamespaceManager istifadə edin:
<catalog xmlns="http://books.example.com">
<book>
<title>Algorithms</title>
</book>
</catalog>
doc.LoadXml(xml);
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("b", "http://books.example.com");
XmlNodeList books = doc.SelectNodes("/b:catalog/b:book", nsmgr);
foreach (XmlNode book in books)
Console.WriteLine(book.SelectSingleNode("b:title", nsmgr)?.InnerText);
8. DOM vasitəsilə XML modifikasiyası
"Canlı" node əlavə etmək
Birinci istifadəçiyə yeni <email> elementi əlavə edək:
XmlElement email = doc.CreateElement("email");
email.InnerText = "olga@gmail.com";
olga.AppendChild(email);
Atributları dəyişdirmək
olga.SetAttribute("id", "99"); // İndi id="99"
XPath ilə node‑ları silmək
XmlNodeList nodesToRemove = root.SelectNodes("user[age<20]");
foreach (XmlNode node in nodesToRemove)
root.RemoveChild(node);
9. Faydalı nüanslar
Axtarış və kütləvi struktur dəyişdirmə
Tutaq ki, sizə böyük XML gəlir və orada müxtəlif <record type="..."> elementləri var. Yalnız atributu type‑i "customer" olanları saxlamaq və hər birinə child olaraq <status>active</status> əlavə etmək lazımdır.
XmlNodeList customerNodes = root.SelectNodes("record[@type='customer']");
foreach (XmlElement record in customerNodes)
{
XmlElement status = doc.CreateElement("status");
status.InnerText = "active";
record.AppendChild(status);
}
XML node ağacı (DOM)
users
├─ user (id="1")
│ ├─ name ("Olga")
│ └─ age ("28")
├─ user (id="2")
│ ├─ name ("Igor")
│ └─ age ("35")
XPath üzrə seçim nümunəsi
| XPath‑sorgu | Nə qaytaracaq |
|---|---|
|
Birinci istifadəçi (id="1") |
|
Son istifadəçi (id="2") |
|
30‑dan böyük olanlar (Igor) |
|
id="2" olan istifadəçi |
Praktik tətbiq
- Köhnə API‑lərlə integrasiyalar. Bir çox dövlət şirkətində və bankda SOAP/XML hələ də geniş istifadə olunur. Böyük XML cavabında nəyisə sürətlə tapıb dəyişmək onlarla saatı xilas edə bilər.
- Məlumatların miqrasiyası. Bir sistemdən digərinə keçərkən çox vaxt XML parse edib çətin seçkilər, transformasiyalar və kütləvi dəyişikliklər etmək lazım gəlir.
- Excel‑ə import‑export. Bir çox B2B məhsuluna hələ də XML daxil olur. Orada XPath — böyük data modeli yaratmadan lazım olanı əldə etməyin sürətli yoludur.
10. Səhvlər, nüanslar və tipik tələlər
NullReferenceException: Məsələn, mövcud olmayan elementə müraciət etsəniz — el["something"].InnerText — və belə child yoxdursa, xəta alacaqsınız. Həmişə null üçün yoxlayın.
XPath və nesting: Unutmayın ki, ifadə başlanğıc / olmadan cari node‑un potomları arasında axtarır, / ilə isə sənədin kökündən başlayır. Müxtəlif start nöqtələri nəticə olmamasına gətirə bilər, baxmayaraq ki, data mövcuddur.
Namespace ilə işləmək: Əgər XmlNamespaceManager istifadə etməsəniz, XPath sorğuları xmlns olan XML‑lərdə boş qaytara bilər.
İterasiya zamanı modifikasiya: SelectNodes nəticəsinə əsasən node‑ları silmək istəyirsinizsə, əvvəlcə onları massivə yığın, sonra iterasiya edin — yoxsa kolleksiya iterasiya zamanı dəyişər və səhvlər yaranar.
Text və element node‑larının fərqi: Elementlər arasında boşluq və line‑break kimi text node‑lar ola bilər. Sərt seçim üçün yalnız XmlElement istifadə edin və ya NodeType ilə filtr tətbiq edin.
GO TO FULL VERSION