XLINQ (Xml Language Integrated Query)
temel olarak LINQ modelinin Xml üzerine uyarlanabilmesini
hedeflemektedir. Bildiğiniz gibi LINQ projesi ile, IEnumerable<T>
arayüzünü uygulamış .Net nesneleri üzerinde dil ile tümleştirilmiş
sorgulamalar gerçekleştirilebilmektedir. Microsoft aynı sorgu yapısını,
veritabanı objelerinin programlama ortamında nesnel olarak ifade
edilebildiği varlıklar(entities) üzerinde kullanılabilmesini de DLINQ
(Database Language Integrated Query) ile
sağlamaktadır. (DLINQ ile ilgili özet bilgileri bu
makalemden
bulabilirsiniz.) XLINQ ise, yine dil tabanlı sorgulama özelliklerini alıp bunların XML
verileri üzerinden gerçkeştirilebilmesini sağlmayayı amaçlamaktadır. Xml
verilerinde dil tabanlı sorgular yapılabilmesinin dışında, var olan döküman
nesne modeline (Document Object Model -DOM), XPath ve Xslt kavramlarına
ek olacak şekilde yeni fonksiyonelliklerde gelmektedir. Örneğin bir Xml
verisini bellek üzerinde oluşturmak için XDocument isimli yeni
bir tipin
yapıcı metodlarından faydalanabiliriz. Dahada ileri gidersek, XLINQ yu
DLINQ ile tümleşik olacak şekilde kullanabiliriz. Bunun anlamı,
veritabanı objelerinin nesnel olarak ifade edildiği varlıkları LINQ ile
sorgulayıp, Xml formatında sonuç kümelerini çalışma zamanında (runtime) elde edebileceğimizdir. DLINQ
da olduğu gibi, XLINQ da kendi içerisinde C# 3.0 ın yeniliklerini
barındırmakta ve kullanmaktadır.
 |
XLINQ ile ilgili denemeleri
LINQ Preview
ekini kullanarak Vs.Net 2005 üzerinden deneyebilirsiniz. |
XLINQ için gerekli tipler, System.Xml.XLinq isim alanı altında yer
almaktadır. Bir
Xml dökümanı ve içerisinde yer alabilecek elemanlar göz önüne
alındığında bunların karşılıklarının yönetimli kod (managed code)
tarafında X harfi ile başlayan
tiplerle ifade edildiğini görebiliriz. Örneğin Xml elementlerini
XElement tipi, nitelikleri (Attribute) XAttribute tipi karşılamaktadır.
System.Xml.XLinq isim alanında (namespace) bu iki tipin dışında aşağıdaki tabloda bir kısmı
verilen diğer yönetimli tiplerde yer almaktadır.
|
Tip Adı |
Xml Karşılığı |
| XDocument |
Bir Xml dökümanı içermekle
sorumludur. XDocument sayesinde sıfırdan Xml içerikleri bellek
üzerinde oluşturulabilir, kaydedilebilir yada var olan bir Xml
içeriği belleğe yüklenebilir. |
| XElement |
Xml dökümanlarında yer alan
element lerin yönetimli kod tarafındaki karşılığıdır. |
| XAttribute |
Xml dökümanlarında yer alan
niteliklerin (attribute) yönetimli kod tarafındaki karşılığıdır. |
| XComment |
Xml dökümanlarında
kullandığımız yorum satırlarını yönetim kod tarafında kullanımamızı
sağlar. |
| XNode |
Xml dökümanı içerisinde, node
(boğum) olarak ifade edilebilecek her türden elemanı yönetimli
kod tarafında ele alabilmek amacıyla kullanılır. |
| XProcessingInstruction |
Xml dökümanlarının başında yer
alan processing instruction ların managed tarafta ele
alınabilmesini sağlar. Bu iş için XDecleration sınıfındanda
yararlanılmaktadır. Örneğin Xml dökümanları başına standard
olarak gelen versiyon numarası , encoding gibi bilgileri bu
XDecleration yardımıyla kod tarafında tanımlayabiliriz. |
| XText |
Çoğunlukla CData (Character
Data) bölümlerinin yada birleştirimiş metinlerin yönetimli kod
tarafında
ele alınabilmesi için kullanılır. |
| XNamespace |
Xml içerisinde yer alan isim
alanlarının yönetimli kod tarafında ele alınabilmesini sağlar. |
| XContainer |
XDocument ve XElement
sınıflarının türetildikleri abstract sınıftır. Özellikle Xml
dökümanı üzerinde sorgulamalar yapabilmek için gerekli
fonksiyonelikleride sağlar. |
| XDocumentType |
DTD (Document Type
Definitions) yapısının yönetimli kod tarafındaki karşılığıdır. |
| XElementSequence |
LINQ için geliştirilmiş,
genişletişmiş metodları (extension methods) barındıran static
sınıftır. Extension Methods kavramı C# 3.0 ile birlikte
gelmiştir ve var olan framework tiplerine ek metodlar
yazılabilmesini sağlamaktadır. |
Dilerseniz XLINQ ile geliştiricilerin
hayatına girecek bir kaç yeniliği örnekler ile uygulayarak makalemize
devam edelim. İlk olarak bir Xml verisinin bellek üzerinde oluşturulması
sırasında XDocument tipinden nasıl yararlanabileceğimizi göreceğiz. Bu
amaçla yeni bir LINQ Console Application projesi oluşturalım ve
aşağıdaki kod satırlarını yazalım.
using System;
using System.Collections.Generic;
using System.Text;
using System.Query;
using System.Xml.XLinq;
using System.Data.DLinq;
namespace UsingXLINQ
{
class Program
{
static void Main(string[] args)
{
#region Basit
XLINQ Kullanımı
XDocument
xmlBook = new
XDocument(
new
XDeclaration("1.0",
"utf-8", "yes")
, new
XElement("Books"
, new
XElement("Book",
new
XAttribute("ID",
1000)
, new
XElement("Name",
new XText("Her Yönüyle C#"))
, new
XElement("ListPrice",
new XText("50"))
)
, new
XElement("Book",
new
XAttribute("ID",
1001)
, new
XElement("Name",
new XText("C# CookBook"))
, new
XElement("ListPrice",
new XText("45"))
)
)
);
xmlBook.Save("BookWithXLinq.xml");
XElement
element =
XElement.Load("BookWithXLinq.xml");
Console.WriteLine(element.ToString());
#endregion
}
}
} |
İlk dikkatimizi çeken sanıyorumki
XDocument nesnesinin oluşturuluş şekli olsa gerek. XDocument nesnesine
ait yapıcı metod bir Xml verisinin sıfırdan oluşturulabilmesini
sağlayacak şekilde tasarlanmıştır. Dolayısıyla yapıcı metodumuz
içerisinde Xml verimiz için gerekli elemanları teker teker
oluşturabiliriz. Örneğimizdeki XDocument nesne örneğinin yapıcı metodu
(constructor) içerisinde ilk olarak her Xml içeriğinin sahip olması gereken
processing instruction kısmını oluşturuyoruz. Bunu gerçekleştirmek için
XDeclaration sınıfını kullanmaktayız.
Her Xml verisinin bir root elementi
olması gerektiğinden XElement sınıfı ile ilk olarak Books isimli boğumu
tanımlıyoruz. Burada dikkat etmemiz gereken bir nokta var. XElement
sınıfına ait yapıcı metod (constructor) içerisinden yeni XElement yada XAttribute nesne
örneklerini oluşturabiliyoruz. Dolayısıyla hiyerarşik olarak bir Xml veri ağacını yapıcı metod içerisinde tek
seferde oluşturabilmekteyiz. Çünkü her elementin içereceği diğer
elementleri yapıcıları içerisinde tanımlıyoruz.
Oluşturulan bu Xml içeriği bellek
üzerinde yer alacaktır. Ancak dilersek bu içeriği fiziki bir kaynağada
kaydedebiliriz. Bu amaçlada XDocument sınıfının Save metodu
kullanılır. Tam tersine, fiziki bir Xml dosyasından bir XElement tipi
içerisine yükleme işlemide gerçekleştirebiliri. Örneğimizde içeriği bir
XElement tipine yüklemek amacıyla yine XElement tipinin static Load
metodunu kullanıyoruz. Aslında bir xml içeriğini fiziki bir dosyadan
okumak veya yazmak gibi işlemler zaten .Net içerisindeki bilinen Xml
tiplerininde yapabileceği fonksiyonelliklerdir. Ancak bir Xml içeriğini
yapıcı metod yardımıyla tek seferde oluşturabilme yeteneği XLINQ nun
vadettiği yeniliklerden birisidir. Sonuç itibariyle uygulamamızı
çalıştırdığımızda aşağıdaki ekran görüntüsünü elde ederiz.

Bununla birlikte BookWithXLinq.xml
isimli dosyanında aşağıdaki gibi oluşturulduğunu görebiliriz.

Bellek üzerinde XDocument ile
oluşturulan yada bir XElement tipi içerisine yüklenen Xml verilerine
sonradan eleman eklemek var olan elemanları değiştirmek hatta silmek
gibi işlemleride gerçekleştirebiliriz. Örneğin aşağıdaki kod parçasında
belleğe aldığımız Xml içeriğine yeni bir Book elemanı, alt elamanları
ile niteliği eklenmektedir.
XElement
newBook = new
XElement("Book",
new
XAttribute("ID",
1005)
, new
XElement("Name",
new
XText("Developing
XLINQ"))
, new
XElement("ListPrice",
new
XText("80"))
);
xmlBook.Element("Books").Add(newBook);
Console.WriteLine(xmlBook.ToString()); |
Books Xml içeriğine yeni bir kitap
eklemek için XElement tipinden ve yapıcı metodundan faydalanmaktayız.
Dikkat ederseniz Book boğumunu oluştururken içerisine ID attribute unu,
Name ve ListPrice elemanları ile bunların içeriklerini eklemekteyiz.
Text tabanlı içeriğin eklenebilmesi içinde XText tipinden
yararlanıyoruz. Bu tarz bir kullanım görsel arabirime sahip windows veya
web tabanlı uygulamalarda hatta mobil uygulamalarda oldukça işe
yarayacaktır. Öyleki Xml verisinin değerleri kullanıcı tarafından ele
alınan bileşenlerden seçilerek elde edilebilir.
XElement tipi ile oluşturulan Xml
elemanını var olan XDocument nesnesinin işaret ettiği Xml içeriğine
eklemek için ise önce Books elemanına gidilmektedir. Bu amaçla
Element metodu kullanılmış ve parametre olarak gidilecek elemanın
adı verilmiştir ki buda root tur. Element metodu geriye bir XElement
döndürmektedir. Yani çalışma zamanında Books root elemanını işaret
etmektedir. Bunun arkasından gelen Add metodu yardımıyla, bir üst
satırda oluşturulan yeni Book elemanı root elamının içeriğine dahil
edilmektedir. Programı bu haliyle çalıştırdığımızda aşağıdaki sonucu
elde ederiz. Gördüğünüz gibi yeni oluşturduğumuz eleman var olan Xml
içeriğinin sonuna eklenmiştir.

Gelelim dil tabanlı sorgulama
özelliklerinin XLINQ içerisindeki yerine. LINQ getirdiği imkanlar
sayesinde veriler üzerinde sorgulamalar yapmamızı kolaylaştıracak
yenilikler getirmektedir. Buna göre özellikle Sql den aşina olduğumuz
select, where, orderby, from, sum gibi pek çok kavramı, IEnumerable<T>
dan türemiş .Net tiplerinin sunduğu veriler üzerinde, veritabanı
kaynaklarının nesnel karşılıklarının sunulduğu varlıklar (entities)
üzerinde kullanabilmemiz mümkündür. Bu yenilikler kendisini Xml
verilerinin sorgulanmasında da göstermektedir. Örneğin, aşağıdaki gibi
örnek bir Xml içeriğimiz olduğunu düşünelim.
<?xml
version="1.0" encoding="utf-8" ?>
<Personelimiz>
<Personel ID="1">
<SicilNo>190002</SicilNo>
<Ad>Burak Selim</Ad>
<Soyad>Şenyurt</Soyad>
<Maas>1000</Maas>
</Personel>
<Personel ID="2">
<SicilNo>1903402</SicilNo>
<Ad>Elma</Ad>
<Soyad>Soz</Soyad>
<Maas>5000</Maas>
</Personel>
<Personel ID="3">
<SicilNo>1401202</SicilNo>
<Ad>Kevın</Ad>
<Soyad>Dankin</Soyad>
<Maas>4500</Maas>
</Personel>
<Personel ID="4">
<SicilNo>230002</SicilNo>
<Ad>Carim Abdul</Ad>
<Soyad>Cabbar</Soyad>
<Maas>500</Maas>
</Personel>
<Personel ID="5">
<SicilNo>121302</SicilNo>
<Ad>Mayk</Ad>
<Soyad>Cordın</Soyad>
<Maas>2000</Maas>
</Personel>
</Personelimiz> |
Personel.xml isimli dosyada tutulan bu
içerikte bir Personelin ID, Sicil Numarası, Ad, Soyad, Maas bilgileri
tutulmaktadır. Bu Xml içeriğini belleğe alan bir uygulamada çok doğal
olarak bazı sorgulamalar yapmak isteyebiliriz. Örneğin maaşı belirli bir
değerin üzerinde olanları bu Xml dökümanı içerisinden çekmek
istediğimizi düşünelim. Aşağıdaki kod parçası bu işlemin nasıl
gerçekleştirilebileceğini göstermektedir.
Console.WriteLine("Maaş değeri ");
double maas=Convert.ToDouble(Console.ReadLine());
XDocument docPersonel=XDocument.Load("..\\..\\Personel.xml");
XElement elements=new XElement("PersonelListe",
from
pers in
docPersonel.Elements("Personelimiz").Elements("Personel")
where
(double)pers.Element("Maas")>=maas select pers
);
Console.WriteLine(elements.ToString()); |
Kod içerisinde LINQ ifadesinin nasıl
kullanıldığına dikkat edelim. Uygulamamız kullanıcından maaş bilgisini
aldıktan sonra ilk olarak Personel.xml isimli dosya içeriğini belleğe
bir XDocument nesnesi yardımıyla alıyor. Sonrasında ise
docPersonel nesnesi üzerinden bir LINQ sorgusu gerçekleştiriliyor ve
sonuçlar bir XElement nesne örneğinde tutulacak şekilde alınıyor.
Uygulama çalıştırıldığında ve maaş değeri olarak 2000 değeri
girildiğinde aşağıdaki ekran görüntüsü ile karşılaşırız.

LINQ sorgusu, XElement tipine ait nesne
örneği oluşturulurken ikinci parametre içerisinde kullanılmıştır. Sql
kullanıcıları için from, where ve select gibi anahtar kelimelerinin yeri
biraz tuhaf gelebilir. Aslında yukarıdaki işlemi Sql dilinde
düşündüğümüzde, "Select * From Personel Where Maas>=2000"
gibi bir ifadeyi göz önüne alabiliriz. LINQ da ise durum biraz daha
farklı olmakla birlikte oldukça anlaşılır sorgular
oluşturulabilmektedir. Dolayısıyla Xml verilerini LINQ nun sağladığı
bütün imkanlar ile sorgulama şansına sahibiz. Şüphesizki bu imkanlar,
özellikle XPath ve XQuery gibi sorgulama teknolojilerin üzerine
gelen oldukça esnek ve güçlü bir yapı olarak karşımıza çıkmaktadır. İşin
güzel yanı burada ele aldığımız LINQ sorgularının anahtar kelimelerinin
ve kullanım standardlarının , LINQ, XLINQ, DLINQ için aynı olmasıdır.
Şimdi XLINQ nun DLINQ ile olan yakın
ilişkisine bir göz atalım. Bildiğiniz gibi DLINQ mimarisinde, veritabanı
nesnelerini uygulama tarafında temsil ettiğimiz objeler üzerinde LINQ
sorguları çalıştırabilmekteyiz. Yani bir veritabanı tablosunu uygulama
ortamında nesnel olarak ifade eden bir veri üzerinde dil tabanlı
sorgular çalıştırabilmekteyiz. XLINQ ilede, DLINQ nun sunduğu varlıklar
(entity) üzerinde yapacağımız LINQ sorguları sonucu elde edilen sonuç
kümelerini çalışma zamanında Xml içeriği haline getirebilme şansına
sahibiz. Yani DLINQ ve XLINQ özelliklerini bir arada ele alabiliriz. Bu
konuyu daha net anlayabilmek için Northwind veritabanının entity
karşılıklarını ele alacağımız bir örnek ile devam edeceğiz. LINQ Preview
ile birlikte, DLINQ içerisinde kullanılan varlıkları(entities) yazmak
yerine kolayca hazırlayabileceğimiz bir araç (tool) gelmektedir.
SqlMetal isimli bu aracı aşağıdaki gibi komut satırından
çalıştırabiliriz.
| D:\Program
Files\LINQ Preview\Bin>sqlmetal
/server:localhost
/database:Northwind
/code:NorthwindBase.cs |
Bu durumda NorthwindBase.cs isimli bir
sınıf oluşturulacak ve bizim için gerekli tüm sınıflar bu kaynak kod
içerisine dahil edilecektir. SqlMetal aracı yardımıyla oluşturulan bu
sınıfın içeriğine Class Diagram yardımıyla baktığımızda aşağıdaki
ekran görüntüsüne benzer bir içerik ile karşılaşırız.

Hatırlayacağınız gibi DLINQ konusunu
incelediğimiz makalemizde yukarıdakine benzer bir yapıyı kendimiz
yazarak geliştirmeye çalışmıştık. SqlMetal aracı yardımıyla oluşturulan
NorthwindBase.cs dosyasını uygulamamıza ekledikten sonra aşağıdaki
kodları yazalım.
Console.WriteLine("Ürün Fiyatı ");
decimal fiyat=Convert.ToDecimal(Console.ReadLine());
Northwind
nrth = new
Northwind("data
source=localhost;database=Northwind;integrated security=SSPI");
XElement
urunler =new
XElement("Urunler",
from urn in
nrth.Products where urn.UnitPrice> fiyat orderby urn.ProductName
select
new XElement("Urun",
new
XAttribute("ID",urn.ProductID),
new
XAttribute("Ad",
urn.ProductName),
new
XAttribute("BirimFiyat",
urn.UnitPrice)
)
);
urunler.Save("Urunler.xml");
Console.WriteLine(urunler.ToString()); |
Uygulamamızda kullanıcından bir fiyat
bilgisi alıyoruz. Sonrasında ise Northwind sınıfımızı bağlantı için
gerekli bilgi ile oluşturuyoruz. Bu işlemin arkasında Urunler isimli bir
root eleman içerecek bir XElement nesnesi örnekliyoruz ve ikinci
parametre içerisinde yine dil tabanlı bir sorgus cümleciği kullanıyoruz.
Bu sefer Products tablosundan gelen (ki bu tablo Northwind sınıfı
içerisinde Products isimli bir sınıfa karşılık geliyor) verilerden,
UnitPrice alanı belli bir değerin üzerinde olan satırları ProductName
alanına göre sıralayıp çekiyoruz. Çekilen verileri Urun isimli bir
XElement içerisinde XAttribute sınıfı yardımıyla nitelik
olarak oluşturuyoruz. Sonrasında ise deneme olması amacıyla elde edilen
XElement i fiziki bir dosyaya kaydediyor ve uygulama ekranına
basıyoruz. Buna göre uygulama çalıştığında aşağıdaki ekran görüntülerini
elde ederiz.

Üretilen Xml dosyası içeriği ise
aşağıdaki gibi olacaktır. Dikkat ederseniz, XElement sınıfı ile
tanımladığımız nesne örneğinin sunduğu Xml içeriğinde ID, Ad, BirimFiyat
isimli nitelikler (attributes) değerlerini Products sınıfına ait
ProductID, ProductName, UnitPrice özelliklerinden alacak şekilde
oluşturulmuş ve Urun isimli eleman (element) içerisinde toplanmışlardır.

Görüldüğü gibi Xml dosyası ve ekran
çıktısında UnitPrice alanının değeri 90 birimin üzerinde olanları elde
ettik. Burada önemli olan nokta, dil tabanlı sorgulamayı kullanarak,
varlıklar (entities) üzerinden bir sorgulama yapmamız ve sonuçları
çekerken bunları XElement, XAttribute gibi tipler yardımıyla bir Xml
içeriğine dönüştürmemizdir. Elde edilen bu Xml içeriği platformlar
arasında hareket edebilecek, fiziki kaynaklar üzerine yazılabilecek,
hatta uygulamaların görsel bileşenlerine bağlanabilecek (örneğin
XmlDataSource yardımıyla bir TreeView kontrolüne yada bir GridView
kontrolüne) hale getirilmektedir. XLINQ yukarıdaki örneklerde
üzerinde durmaya çalıştığımız yenilikler dışında pek çok özellik daha
içermektedir. Bunlar LINQ Preview yardımıyla gelen dökümantasyondan da
bulabilirsiniz. Özetle XLINQ, dil tabanlı sorguları ve Xml ile ilgili
yeni fonksiyonellikleri biz geliştiricilerin kullanımına sunmayı
hedeflemektedir. Böylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde görüşünceye
dek hepinize mutlu günler dilerim.
Örnek kod için tıklayın.
Burak Selim ŞENYURT
selim@bsenyurt.com
Makale:
C# 3.0 - İlk Bakışta XLINQ .NET 3.0 ve .NET 3.5 Özel Bölümü Burak Selim Şenyurt
|