C# Linq To XML ile XML Dosyalarla Çalışmak, dersim ile C# eğitim setime devam ediyorum. Bu dersimizde C# ile XML dosyalar üzerinde LINQ teknolojisini kullanma işlemine bakacağız.
Öncelikle Linq nedir ona bakalım.
C# LINQ Nedir?
İngilizce açılımı Language INtegrated Query olan ve Türkçe anlamı, Programlama Diliyle Bütünleştirilmiş / Entegre Edilmiş Sorgu olan HASKELL, XML, HTML ve SQL gibi bildirimsel (Declerative) yazım şekli (sözdizimi, syntax) kullanan teknolojidir. VS 2008 ve .Net Framework 3.5 ile hayatımıza girmiştir.
LINQ, SQL de yazdığımız gibi sorguları, C# ya da Visual Basic gibi programlama dilleri kullanarak yazabilmemizi sağlar. LINQ kullanarak SQL, XML, Ado.Net ve programlama dillerindeki Diziler (Koleksiyon türünde veriler) üzerinde sorgulama yapabilmemizi sağlar.
Bu dersimizde LINQ teknolojisini XML dosyalar üzerinde nasıl kullanacağımızı göreceğiz.
C# Linq To XML
Öncelikle bir XML dosya hazırlamamız gerekiyor. Ben örnek bir tane hazırladım.
<?xml version="1.0" encoding="utf-8" ?> <PERSONELLER> <Personel> <ID>1</ID> <Ad>Personel 1</Ad> <Maas>5000</Maas> <Departman>Muhasebe</Departman> </Personel> <Personel> <ID>2</ID> <Ad>Personel 2</Ad> <Maas>6000</Maas> <Departman>Bilgi İşlem</Departman> </Personel> <Personel> <ID>3</ID> <Ad>Personel 3</Ad> <Maas>7000</Maas> <Departman>Pazarlama</Departman> </Personel> <Personel> <ID>4</ID> <Ad>Personel 4</Ad> <Maas>8000</Maas> <Departman>Dış Ticaret</Departman> </Personel> <Personel> <ID>5</ID> <Ad>Personel 5</Ad> <Maas>9000</Maas> <Departman>Satın Alma</Departman> </Personel> </PERSONELLER>
BİLGİ: SQL tarafından baktığımızda PERSONELLER tablo adı; Personel ise bu tablodaki bir satır; ID, Ad, Maas, Departman ise tablonun kolonları yerine geçer.
XML dosyamızı hazırladıktan sonra diğer işlemlerimize geçebiliriz.
C# XML verileri GRID ‘e almak
PERSONELLER etiketi bizim Root yani Kök elementimizdir. Yukarıda verdiğim bilgiye istinaden tablo adımızdır. İç etiketler ise Child yani çocuk etiketlerdir. Child etiketlere Attiribute yani özellik ekleyebiliriz ancak onu dersin ilerleyen noktalarında göreceğiz. Şimdi Bu XML dosyamızdaki bilgileri okuyup bir DataGridView nesnesinde gösterelim.
İlk işlem Solition Explorer üzerinden eklediğimiz XML dosyası üzerinde sağ tık yapıyoruz ve Properties menüsüne tıklıyoruz. Açılan ekranda Copy To Out Directory özelliğini Copy Always diyoruz. Bu sayede bu xml dosyası Bin/Debug klasörüne kopyalanacak.
Formumuza bir buton ve bir datagridview ekleyelim.
Projemize NameSpace’imizi ekleyelim.
using System.Xml;
string AppPath = System.Windows.Forms.Application.StartupPath; // EXE dosyasının olduğu klasör yolunu verir. private void btn_Bilgileri_Goster_Click(object sender, EventArgs e) { string DosyaPath = AppPath + "\\_010_LINQ_to_XML\\myXML.xml"; DataSet ds = new DataSet(); XmlReader xmlFile; xmlFile = XmlReader.Create(DosyaPath, new XmlReaderSettings()); ds.ReadXml(xmlFile); dataGridView1.DataSource = ds.Tables[0]; }
İlk olarak Projemizin EXE dosyasının olduğu klasör yolunu aldık. Sonrasında buton_click eventi içerisinde xml dosyamızın tam yolunu belirttik. Bir dataset tanımlayarak xml dosyamızı XML reader ile okuyup dataset’e yükledik ve datagirdview üzerinde gösterdik.
Ekran görüntüsünde gördüğünüz gibi verileri başarı ile aldık.
C# XML Element ve Elements
Formumuza bir listbox nesnesi ekleyelim ve XML element ve elements sınıflarını kullanarak verileri alalım. Aldığımız verileri de listbox üzerinde gösterelim.
Bu NameSpace’i projemize ekleyelim.
using System.Xml.Linq;
Şimdi Projemin kodlarında biraz değişikliğe gittim ve şu şekilde düzenledim.
Yukarıdaki örnekte yer alan gride doldurma kodlarımı bir parametre alan bir void ‘e aldım.
void XML_to_GridView(string _DosyaPath) { DataSet ds = new DataSet(); XmlReader xmlFile; xmlFile = XmlReader.Create(_DosyaPath, new XmlReaderSettings()); ds.ReadXml(xmlFile); dataGridView1.DataSource = ds.Tables[0]; }
buton_Click eventi içerisinde de dosyanın yolunu alıp parametre olarak gönderdim.
private void btn_Bilgileri_Goster_Click(object sender, EventArgs e) { // Her işlemde kullanacağımızdan bunu en dışa aldık. string DosyaPath = AppPath + "\\_010_LINQ_to_XML\\myXML.xml"; XML_to_GridView(DosyaPath); // XML deki Verileri GRID'e Doldurmak }
Bu değişiklikleri yaptıktan sonra şimdi vereceğim örneği de bir parametre olan bir metod olarak yazdım ve yine buton_click eventi içerisinde aldım.
void XML_Element_Elements(string _DosyaPath) { XDocument xDoc = XDocument.Load(_DosyaPath); // XML dosyaımızı XDocument nesnesine yükledik. foreach (XElement urun in xDoc.Element("PERSONELLER").Elements("Personel")) // PERSONELLER root node ve onun içindeki Personel child node lerini gezeceğiz. { listBox1.Items.Add(string.Format("{0} - {1} - {2} - {3}", urun.Element("ID").Value, // PERSONELLER > Personel > ID urun.Element("Ad").Value, // PERSONELLER > Personel > Ad urun.Element("Maas").Value, // PERSONELLER > Personel > Maas urun.Element("Departman").Value // PERSONELLER > Personel > Departman )); } }
Sonra buton_click eventini düzenleyelim.
private void btn_Bilgileri_Goster_Click(object sender, EventArgs e) { // Her işlemde kullanacağımızdan bunu en dışa aldık. string DosyaPath = AppPath + "\\_010_LINQ_to_XML\\myXML.xml"; XML_to_GridView(DosyaPath); // XML deki Verileri GRID'e Doldurmak XML_Element_Elements(DosyaPath); // XML deki Verileri ListBox'a Doldurmak }
İkinci örneğimizde, XML dosyayı node (Nokta, Element) üzerinden tek tek gezerek okuma yöntemine baktık. Bazı XML dosyaları çok karışık bir halde olduğundan okunması ilk örneğimizdeki gibi basit bir şekilde okunamıyor. İkinci örneğimizde olduğu gibi döngülerle okunabiliyor.
C# XML Element Attiribute
Şimdi de satırlarımıza yani child elementlere bir attiribute ekleyelim. Ben attiribute olarak Aktif özelliği ekleyeceğim ve özelliği True olarak ayarlayacağım. Okuma işlemini yaparken de sadece True olanları okuyacağım. Bu örnek ikinci örneği temel alacaktır.
XML dosyamızın son hali
<?xml version="1.0" encoding="utf-8" ?> <PERSONELLER> <Personel Aktif ="True"> <ID>1</ID> <Ad>Personel 1</Ad> <Maas>5000</Maas> <Departman>Muhasebe</Departman> </Personel> <Personel Aktif ="True"> <ID>2</ID> <Ad>Personel 2</Ad> <Maas>6000</Maas> <Departman>Bilgi İşlem</Departman> </Personel> <Personel Aktif ="True"> <ID>3</ID> <Ad>Personel 3</Ad> <Maas>7000</Maas> <Departman>Pazarlama</Departman> </Personel> <Personel Aktif ="False"> <ID>4</ID> <Ad>Personel 4</Ad> <Maas>8000</Maas> <Departman>Dış Ticaret</Departman> </Personel> <Personel Aktif ="False"> <ID>5</ID> <Ad>Personel 5</Ad> <Maas>9000</Maas> <Departman>Satın Alma</Departman> </Personel> </PERSONELLER>
Aktif özellikleri True olan child elementleri okuyacak metodumuzu vereyim.
void XML_Node_Attiribute(string _DosyaPath) { XDocument xDoc = XDocument.Load(_DosyaPath); // XML dosyaımızı XDocument nesnesine yükledik. foreach (XElement urun in xDoc.Element("PERSONELLER").Elements("Personel")) // PERSONELLER root node ve onun içindeki Personel child node lerini gezeceğiz. { XAttribute att = urun.Attribute("Aktif"); if (att != null && att.Value == "True") { listBox_attiribute.Items.Add(string.Format("{0} - {1} - {2} - {3}", urun.Element("ID").Value, // PERSONELLER > Personel > ID urun.Element("Ad").Value, // PERSONELLER > Personel > Ad urun.Element("Maas").Value, // PERSONELLER > Personel > Maas urun.Element("Departman").Value // PERSONELLER > Personel > Departman )); } } }
Önceki örneğimizden farklı olarak XAttribute sınıfını kullanarak elementlerin attirbute lerine ulaşıp kullanabiliyoruz.
buton_click eventimizin son hali,
private void btn_Bilgileri_Goster_Click(object sender, EventArgs e) { // Her işlemde kullanacağımızdan bunu en dışa aldık. string DosyaPath = AppPath + "\\_010_LINQ_to_XML\\myXML.xml"; XML_to_GridView(DosyaPath); // XML deki Verileri GRID'e Doldurmak XML_Element_Elements(DosyaPath); // XML deki Verileri ListBox'a Doldurmak XML_Node_Attiribute(DosyaPath); // XML deki Aktif=True olan Verileri ListBox'a Doldurmak }
Gördüğünüz gibi, 4. ve 5. personellerimizin Aktif attiribute ‘lerini False yaptığımızdan onlar listelenmedi.
C# LINQ to XML Tüm Child Elementleri Okuma
BİLGİ: Personel elementi, PERSONELLER root elementinin child elementidir (Çocuğudur). Ad elementi ise Personel elementinin child elementidir.(Çocuğudur)
Bu bilgiye istinaden, elimizdeki xml dosyasından sadece Ad bilgilerini okuyalım. PERSONELLER elementinden Personel elementine, Personel elementinden de Ad elementine ulaşıp XML dosyasındaki tüm Personel elementlerinin Ad elementini okuyalım.
NOT: Burada kodlarımı biraz daha değiştirdim. Bu metodlar string türünde bir parametre alıyordu. Bu parametre de xml dosyanın yolunu taşıyordu. Ancak her seferinde yeni bir XDocument nesnesi oluştuğundan bu XDocument nesnesini de dışarıya aldım ve metodların parametrelerini XDocument olarak değiştirdim. Form açıldığında XDocument nesnesi oluşuyor. buton_Click eventi içinde de bir kere okuyup okunan dosya bilgisini diğer metodlarda da kullanıyoruz. Bu şekilde performans açısından biraz daha kazanç sağlamış oluyoruz. Bu değişikliklerden kafanız karışmış olabilir ama korkmayın. Bu dersin içeriği de Github projemde yer alacaktır. Son halini oradan görebilirsiniz.
void XML_Tum_Childleri_Oku(XDocument xDoc) { // burada PERSONELLER root elementini yazmamıza gerek yok. Çünkü xDoc.Root. kısmı işimizi çözüyor. foreach (XElement element in xDoc.Root.Elements("Personel").Elements("Ad")) { // burada Attirbute ye bakmadığımızdan tüm isimler gelecektir. listBox_sadece_tek_node.Items.Add(element.Value); } }
Ayrıca her butona tıkladığımızda listbox lar tekrar tekrar dolmasın diye birde temizleme metodu oluşturdum. buton_Click eventi aşağıdaki gibidir.
XDocument xDoc; private void btn_Bilgileri_Goster_Click(object sender, EventArgs e) { Clear_All(); // Her işlemde kullanacağımızdan bunu en dışa aldık. string DosyaPath = AppPath + "\\_010_LINQ_to_XML\\myXML.xml"; xDoc = XDocument.Load(DosyaPath); // Dosya bir kere okunacak ve sürekli kullanılacak // Öncden her metod içerisinde yeni bir nesne oluşuyordu. Şuan teke indirdik. // Her işlemde kullanacağımızdan bunu en dışa aldık. XML_to_GridView(DosyaPath); // XML deki Verileri GRID'e Doldurmak XML_Element_Elements(xDoc); // XML deki Verileri ListBox'a Doldurmak XML_Node_Attiribute(xDoc); // XML deki Aktif=True olan Verileri ListBox'a Doldurmak XML_Tum_Childleri_Oku(xDoc); // XML deki tüm Personel child elementlerdeki Ad bilgisini okuduk. } void Clear_All() { listBox_attiribute.Items.Clear(); listBox_normal.Items.Clear(); listBox_sadece_tek_node.Items.Clear(); dataGridView1.DataSource = null; }
BİLGİ: XML Element ve Elements farklıdır. Element tek bir elementi döndürürken; Elements IEnumerable<XElement> döndürür. Daha açık bir şekilde belirtmem gerekirse; Yukarıdaki örneğimizde Root.Elements değil de Root.Element kullansaydık sadece ilk Personel Child elementindeki Ad bilgisi gelirdi. Yani sadece bir tane Ad gelirdi. Elements dediğimizde tüm Personel Element lerinin Ad bilgileri geliyor.
C# LINQ to XML Sum, Count, Avg
Sum = Toplam
Count = Adet Sayısı, Satır Sayısı, Kayıt Sayısı
Avg = Average, Ortalama
Şimdi bu işlemleri görelim. Forma 3 label ve 3 textbox ekleyelim. Alacğaımız bilgileri bu textbox nesnelerine yazdıracağız.
void XML_sum_count_avg(XDocument xDoc) { // PERSONELLER kök elementi altında sadece Personel elementleri yer aldığından dolayı // xDoc.Root.Elements().Sum(....) şeklinde yazarak Maas toplamlarını alabiliriz. double toplamFiyat = xDoc.Root.Elements("Personel").Sum(element => double.Parse(element.Element("Maas").Value)); txt_sum.Text = toplamFiyat.ToString(); int toplamAdet = xDoc.Root.Elements("Personel").Count(); txt_count.Text = toplamAdet.ToString(); double maasOrtalamasi = xDoc.Root.Elements("Personel").Average(element => double.Parse(element.Element("Maas").Value)); txt_avg.Text = maasOrtalamasi.ToString(); }
Örnekte gördüğünüz gibi Sum, Count ve Avg bilgilerini almak aslında bu kadar kolay.
Birde Aktif özellikleri True olanları nasıl yazdıracağımıza bakalım.
void XML_sum_count_avg_Attirubte(XDocument xDoc) { // PERSONELLER kök elementi altında sadece Personel elementleri yer aldığından dolayı // xDoc.Root.Elements().Sum(....) şeklinde yazarak Maas toplamlarını alabiliriz. double toplamFiyat = xDoc.Root.Elements().Where(xe => xe.Attribute("Aktif").Value == "True").Sum(urun => double.Parse(urun.Element("Maas").Value)); txt_sum_true.Text = toplamFiyat.ToString(); int toplamAdet = xDoc.Root.Elements().Where(xe => xe.Attribute("Aktif").Value == "True").Count(); txt_count_true.Text = toplamAdet.ToString(); double maasOrtalamasi = xDoc.Root.Elements().Where(xe => xe.Attribute("Aktif").Value == "True").Average(element => double.Parse(element.Element("Maas").Value)); txt_avg_true.Text = maasOrtalamasi.ToString(); }
Ekran görüntüsü de,
C# LINQ to XML Select, Order By
Select kullanarak tüm adları çekelim ve order by ile tersten sıralayarak bir listbox’a dolduralım
void XMl_Select_Order_By(XDocument xDoc) { // A-Z sıralama OrderBy, Z-A sıralama OrderByDescending string[] Ad = (xDoc.Root.Elements().Select(xe => xe.Element("Ad").Value).OrderByDescending(ad => ad).ToArray()); // listbox nesnesinin datasource suna Array List'i atayarak dizideki tüm verilerin yüklenmesini sağlıyoruz. listBox_select_order_by.DataSource = Ad; }
Ekran görüntüsü,
Gördüğünüz gibi kayıtlar Descending yani tersten sıralandı.
T-SQL karşılığı şudur
Select Ad From PERSONELLER order by Ad Desc
C# LINQ to XML Group By
Şimdi XML dosyamıza 5 tane daha personel ekleyelim ve her departmanda iki personel olacak şekilde ayarlayalım. İşlemi yaptıktan sonra da kodlarımızı yazalım ve yine bir listbox’ta gösterelim.
void XML_Select_Group_By(XDocument xDoc) { foreach (var grup in xDoc.Root.Elements().GroupBy(xe => xe.Element("Departman").Value)) { listBox_Group_by.Items.Add( grup.Key + " : " + grup.Sum(xe => double.Parse(xe.Element("Maas").Value)) ); } }
Ekran görüntüsü de
T-SQL karşılığı şudur
Select Departman, sum(Maas) From PERSONELLER group by Departman
***
Tüm örneklerde ve uygulamadan aldığım ekran görüntülerine bakarak bu işlemleri ne kadar basit ve kolayca yapılabildiğini görüyorsunuz. Şahsen ben bu tarz işlemleri sql üzerinden yapmayı tercih ediyorum. Bunun en büyük sebebi ise tüm yükü C# üzerinde atmaktansa SQL server ile paylaştırmanın daha mantıklı olduğunu düşünmemdir.
Ancak bazı durumlarda SQL server kullanamıyor olabiliriz. Ya da projemiz gereği SQL Server kullanmamamız gerekebilir. O yüzden böylesi durumlarda LINQ teknolojisi kullanmak gerekebiliyor.
Ek olarak Projenin yayınladığım versiyonunda küçük bir değişiklik yaptım. ;) Projeye ulaştığınızda görebilirsiniz.
C# Linq To XML ile XML Dosyalarla Çalışmak, dersimizde bu kadar arkadaşlar. Uzun zamandır böyle uzun bir ders yazmamıştım. Umarım sizler içinde faydalı olmuştur. Diğer derslerimizde görüşmek üzere.
Bence çok güzel ve açıklayıcı bir ders oldu. Bu dersimde o projenin içerisinde bir klasör olarak yerini almıştır. Buraya tıklayarak projeye ulaşabilirsiniz.
C Sharp Eğitim Seti eğitimi sayfasına gitmek için tıklayınız.
Sağlıcakla ve takipte kalın. ;)