BilgiTeknoloji.net    
b i l g i   t e k n o l o j i   y a z ı l ı m

Ana Sayfa

Marjinal XML Access Pratik Uygulamalar Projeler Ekonometri Dilimiz Çetrefil İletişim
 

XPath


XSL belgelerinde işlenecek öğeler, doğrudan yol ve koşul belirtilerek seçilebilir. Çoğunlukla select deyimiyle birlikte kullanılan bu koşullar ya da yol tanımları aslında XPath dilinin kapsamına girer. Bir döngü içine dahil edilecek düğümlerin seçilmesi için gerekli tanımları yapmak XPath'in görevlerindendir.

Düğüm listesi oluşturma dışında yardımcı birtakım işlevler kullanılarak yeni değerler üretilebilir, karşılaştırmalar yapılabilir. XSL dışında MSXML'deki DOM nesnesi de süzme işlemi yapmak için XPath'in sözdiziminden yararlanır.
 

GENEL BAKIŞ

XPATH, XML belgelerindeki düğümlerin yolunu tanımlamak için kullanılan bir dildir. Geçen aylardaki XSL ile ilgili yazılarımızda XML'den alınan bilgilerin yazdırılmasını incelemiştik. Bunun için, özellikle SELECT özniteliklerinde kullandığımız deyimler aslında XPATH'in kapsamında yer alır.

XPATH ile XML belgelerindeki her düğümün yolu belirtilebilir, bu yapılırken süzme işlemi uygulanarak düğüm-kümesi elde edilebilir.

XPath, XSL'de kullanıldığında düğüm kümeleri (node-set), doğru-yanlış değerleri (boolean), sayısal değerler ve metinler üretir. Düğüm kümeleri, doğrudan yol belirtilerek ya da arama ifadesi girilerek elde edilir. MSXML'deki SelectNodes işlevi de, yol tanımına veya süzme koşuluna uyan tüm öğeleri süzerek düğüm kümesi oluşturmaktadır.

XPath'in sözdiziminde temel olarak yol ve süzgeç koşulu belirten farklı bölümler vardır. Öncelikli yol tanımı olacak şekilde süzgeç koşulları, yol tanımındaki düğümlerin sonuna eklenir. Bunun dışında yukarıda ifade ettiğimiz gibi doğru-yanlış, metin ve sayı değerleri XPath deyimleri ile üretilebilir.

Kitap listemize ait XML dosyamızda aşağıdaki gibi kayıtlar olduğunu kursumuzun önceki yazılarından anımsayın.

<KITAPLAR>
   <KITAP SAYFA="350">
      <KOD>1</KOD>
      <KITAPADI>Stratejik İttifak</KITAPADI>
      <YAZAR>Alptekin Dursunoğlu</YAZAR>
      <YAYINEVI>Anka</YAYINEVI>
   </KITAP>
   <KITAP SAYFA="300">
      <KOD>2</KOD>
      <KITAPADI>Kılıç Yarası Gibi</KITAPADI>
      <YAZAR>Ahmet Altan</YAZAR>
      <YAYINEVI>Can</YAYINEVI>
   </KITAP>
    ...
    ...
</KITAPLAR>

XML belgesindeki her öğe aslında bir düğümle temsil edilmektedir ve XPath ile bu düğümlerin herbirine ulaşılabilir. Basitçe, öğe adlarının başına bölü işaretleri getirerek alt öğelere ulaşmak mümkündür.

/KITAPLAR/KITAP/YAZAR

Bu deyim KITAPLAR öğesinden başlayarak tüm KITAP öğelerinin altındaki YAZAR öğelerini seçer. Bu tür bir ifadeyi aslında bir süzgeç olarak ele almak gerekir. Özellikle belirtilmediği sürece tüm kitapların tüm yazarları, sadece bir yol (path) ifade eder gibi görünen, fakat aslında yola uygun tüm alternatifleri ifade eden bu deyimin kapsamında yer alır. Sırayla tüm ağaç taranır ve üst seviyesi KITAP, onun da üst seviyesi KITAPLAR olan tüm YAZAR öğeleri seçime dahil edilir ve YAZAR'lardan oluşan süzülmüş bir düğüm kümesi oluşturulur.

Bu açıdan bakıldığında XPath'in yol değil, süzgeç koşulu belirttiğinin söylenmesi doğrudur.

Süzme işlemi, herbir düğüme doğrudan ulaşmayı da sağlayabilir. Örneğin bir düğümün kendi grubu içindeki sırası belirtilerek arama yapılabilir.

/KITAPLAR/KITAP[2]

gibi bir sorgu -ki XPath deyimlerini sorgu olarak nitelendirmek yanlış olmaz- kendi seviyesinde ikinci sırada olan KITAP öğesini işaret eder. (Zaten tüm öğeler içinde bu kurala uyan tek öğe vardır.)
 

DOM VE XSL'DE XPATH KULLANIMI

XPath dili, XSL dışında bir kaç dilde daha kullanılabilmektedir. Bununla birlikte MSXML kütüphanesinde de XPath kuralları benimsenmiştir. DOMDocument bileşeninin SelectNodes işlevi ile, XPath sorgusu kullanılarak süzülmüş bir düğüm kümesi elde edilebilir.

DOMNesnesi.SelectNodes("/KITAPLAR/KITAP/YAZAR")

Aslında bu işlev düğümleri yeniden kopyalamayıp, düğümlerin adreslerini saklamaktadır. Yani düğümlerde yapılan değişiklikler asıl belgeye yansıtılır.

'Nesneyi oluşturmak için ya CreateObject, ya da New kullanılmalı.
Dim xml  'As New MSXML2.DOMDocument40
Set xml = CreateObject("MSXML2.DOMDocument.4.0")
xml.Load "c:\kitaplar.xml"

'Belgenin ilk halini göster.
MsgBox xml.xml

'İkinci kitabın yazarını seç.
Dim nodes  'As IXMLDOMNodeList
Set nodes = xml.selectNodes("/KITAPLAR/KITAP[2]/YAZAR")

'İkinci kitabın yazarı değiştiriliyor.
nodes.Item(0).Text = nodes.Item(0).Text & " DEĞİŞTİRİLDİ."

'Belgenin son halini göster. (İkinci kitabın yazarına bakın.)
MsgBox xml.xml

'CreateObject ya da New ile oluşturulan nesneyi bellekten atmak için.
Set xml = Nothing

XSL'de de belli komutlar için XPath deyimleri yazılmaktadır. Value-of, for-each, apply-templates, copy-of, param, sort, variable, with-param ve template deyimlerinin select özniteliğine, if ve when deyimlerinin de test özniteliğine XPath deyimleri yazılır.

SelectNodes işlevi yalnız öğe listesi üretirken XSL'deki bu deyimler XPath'i daha serbest kullanırlar. Öğe listesinin dışında metin ve sayı üreten, doğru-yanlış bilgisi döndüren işlevler kullanılabilir.

Bununla birlikte her iki durum için çok ayrıntılı arama koşulları da tanımlanabilmektedir.


DÜĞÜMLERE ERİŞMEK

XPath'in yol (ya da süzgeç) tanımında her öğenin başka bir öğeye göre yolu bildirilebilir. Bu, göreceli yol tanımıdır. Kökten başlayarak belirtilen yol tanımı ise mutlak yol tanımıdır.

Mutlak yol belirtilirken kök adından başlayarak aradaki tüm düğüm adları yazılır. Yukarıdaki "/KITAPLAR/KITAP/YAZAR" tanımı mutlak yoldur. Varılmak istenen noktaya kadar geçilmesi gereken tüm öğeler tek tek belirtilmiştir. Baştaki bölü işareti yol tanımının kökten başladığını belirtir.

Kolaylık olması için göreceli olarak bu tanımların kısaltılarak yapılması mümkündür. "/" ifadesi bir alt öğeyi temsil ederken "//" kullanıldığında tüm alt öğeler arasından seçim yapılır. Bu durumda yukarıdaki deyimin karşılığı olarak "/KITAPLAR//YAZAR" kullanılabilir. Yani /KITAPLAR öğesinin, iç kısımlarında bulunan /YAZAR adlı tüm alt öğeler temsil edilmiştir. Aynısı //YAZAR şeklinde de ifade edilebilir ve bu belgenin tamamındaki YAZAR öğelerini kapsar. Buradaki bölü işaretlerinin sadece seviye belirtiğine dikkat edin.

Öğeleri seçmek için doğrudan ad belirtmek dışında, tüm öğeleri ifade etmek için yıldız (*) simgesi kullanılır. Yıldız simgesi aynı öbekteki öğeler topluluğunu temsil eder. Aynı öbekte bulunan öğeler birbirlerinin kardeşi olarak kabul edilir.

Kitaplar belgesindeki her KITAP öğesi birbirinin kardeşidir. XML düğümlerini birbirlerine göre (ya da göreceli) olarak tanımlarken insanlarda olduğu gibi akraba ilişkilerini kullanmak akıllıcadır.

Bir öğenin altındaki her öğe onun çocuk öğesi, daha alttaki öğeler de torun öğesidir. Bir üst öğe baba, daha üst öğeler de dede olarak tanımlanabilir. Aynı şekilde her babaya ait çocuk öğeler birbirlerinin kardeş öğesidir. Kardeşlerden üst sırada olanı büyük kardeş, alt sırada olanı da küçük kardeş olarak tanımlanmaktadır.

Bu durumda / simgesinden sonra gelen öğe adı aslında bir çocuk öğesi olarak temsil edilir. Çift bölü de (//) aynı şekilde torun (veya çocuk) öğelere erişmek için kullanılır. Öğeleri temsil ederken bölü işaretleri genellikle tek başlarına yeterli değildir. Öğe adlarını ifade etmek için doğrudan ad belirtilmeli ya da yıldız simgesi gibi, öğeyi işaret eden deyimler kullanılmalıdır.

XPath tanımında sadece "/" ifadesi tek başına kullanıldığında bir liste üretilir ve bu da XML belgesinin ta kendisidir.

Bir düğümü işaret etmek, onun adı dışında birtakım özel işaretleri kullanmakla da mümkün olabilir. Yukarıda bahsettiğimiz yıldız (*) dışında "." ve ".." ifadeleri bunlardan ikisidir.

Tek nokta ifadesi öğenin kendisini, çift nokta da üst öğeyi yani baba olan öğeyi temsil eder. Tabii ki yıldız işareti aynı seviyedeki kardeşleri işaret etmektedir.

/KITAPLAR/* şeklindeki bir deyim, /KITAPLAR'ın bir seviye altındaki tüm çocuk öğeleri kapsar. Zaten bu öğeler kendi aralarında kardeş öğelerdir.

Mutlak yol tanımında ise bu kurallar geçerli değildir. Yol tanımına en baştan başlanıldığı için bu tanım yeterince sade ve anlaşılırdır.

Bu tanımı açık adresler gibi düşünebilirsiniz. Uzaklardan gelen bir mektubun elinize ulaşması için sırasıyla ülke, şehir, semt, cadde, mahalle, sokak, bina numarası ve son olarak daire numarası gibi bilgilerinizin mektubun üzerinde yer alması gerekir.

Evinizi bilmeyen bir arkadaşınıza ise aynı adresi kısa bir tarif şeklinde belirtebilirsiniz. "Mecidiyeköy'deki karakolun arkasından girdikten sonra, şu numaralı binanın üçüncü katı" gibi göreceli bir yol tarifi de, mutlak yol ile aynı işi yapmaktadır.

XPATH de XML öğelerini birbirlerine göre tanımlayabilir. Bunu yaparken mutlak yol tanımından kaçar ve göreceli yol tanımına başvurur.

Bir göreceli yolun tanımlanabilmesi için başvuru (referans - orjin) olacak bir öğe gereklidir. İşte bölü işaretleri arasında kalan kesimler bu esnada başvuru noktası olurlar.

/KITAPLAR//YAZAR ifadesinde torunları belirten // ayıracı göreceli olarak KITAPLAR'ın tüm torunları arasındaki YAZAR'ları hedef alır. Yani KITAPLAR burada başvuru (referans) kaynağıdır. Üstteki adres tarifinde ise başvuru noktası Mecidiyeköy'dür.

XPath ile özniteliklere erişmek de mümkündür. Diğerlerinden farklı olarak, öğe adlarının başında @ işareti bulundurmak, öğe adlarına erişmek ve bunları sorgularda kullanmak için yeterlidir.

/KITAPLAR//@SAYFA ifadesi tahmin edeceğiniz gibi, /KITAPLAR altında bulunan tüm noktalardaki @SAYFA özniteliklerini listeler.

SAYFA="350" 
SAYFA="300" 
SAYFA="280" 
SAYFA="140" 
SAYFA="310" 
... 

Yıldız simgesi de öznitelikler için kullanılabilir. //* ifadesinin belgedeki tüm öğeleri getirdiğini, //@* ifadesinin ise belgedeki tüm öznitelikleri getirdiğini tahmin etmek kolaydır.


GÖRECELİ YOL BELİRTEREK ÖĞELERİ SÜZMEK

Buraya kadar anlatıldığı şekliyle XML belgesi içinde tüm öğelere bir şekilde ulaşılabileceğini, öğenin bulunduğu yere göre süzme yapılabileceğini gördük. XPath bunun dışında koşul belirtilerek süzme yapılmasını da sağlar.

Örneğin öğenin değeri içinde geçen kelimelere göre süzme yapılabilir, bunu yaparken düğüm adedi, sıra numarası gibi bilgilerden faydalanılabilir.

Yıldız simgesinin aynı öbekteki tüm öğeleri işaret ettiğini yukarıda söylemiştik. Bundan faydalanarak aşağıdaki gibi sorgular yapmak mümkündür.

/KITAPLAR/KITAP/*

Tüm /KITAPLAR/KITAP öğelerinin altındaki her şey.

//KITAP/*

Tüm KITAP öğelerinin altındaki her şey. (KITAP öğelerinin kendileri dahil değil.)

//KITAP

Tüm kitap öğeleri ve bunların alt öğeleri.

//*[ .='Orhan Pamuk']

"Orhan Pamuk"a eşit olan her şey.

/KITAPLAR/KITAP[2]/YAZAR

İkinci sıradaki kitabın yazarı. (İlk sıra 1'dir.)

Son örnekte doğrudan bir yol belirtilmiş olmasına rağmen XPath açısından bu, benzeşme olarak değerlendirilir (pattern). Yani tüm öğeler taranırken belirtilen koşula uygun olup olmadıkları araştırılır.

XPath ile daha zengin koşullar da tanımlanabilmektedir. Biribirinden dik çizgi (|) ile ayrılacak şekilde farklı koşullar birleştirilebilir.

/KITAPLAR/KITAP[2]/KITAPADI | /KITAPLAR/KITAP[2]/YAZAR şeklindeki bir ifade ikinci kitabın adını ve yazarını listeleyecektir. Burada farklı iki dizenin | ile birleştirildiğine dikkat edin.

Sıra belirtilen bu tür deyimler kullanılırken dikkat edilmesi gereken şey, sıra bilgisinin sadece kardeş öğeler arasında geçerli olduğudur. Örneğin KITAP öğelerinin ikinci sırada olanı, kardeşleri arasında ikinci sırada olanıdır. Belgenin bütününde birden çok YAZAR öğesi olmasına karşın, üst öğesi KITAP olan öğelerin altında ikinci bir YAZAR öğesi yoktur.

Şartın kardeşler arasında aranmadığını, kardeşlerin aynı adda olanları arasında geçerli olduğunu unutmayın. Bu, /KITAPLAR/KITAP/YAZAR[2] şeklindeki bir ifadenin sonuç vermeyeceği anlamına gelir.

Fakat KITAP altındaki kardeşler arasında, ikinci sırada olan bir öğenin varlığından sözedilebilir.

/KITAPLAR/KITAP/*[2] ifadesi tüm KITAP öğelerinin altında ikinci sırada bulunan her öğeyi süzecektir.

<KITAPADI>Stratejik İttifak</KITAPADI>
<KITAPADI>Kılıç Yarası Gibi</KITAPADI>
<KITAPADI>Şehir Romantiğinin Günlüğü</KITAPADI>
<KITAPADI>Hayvan Çiftliği</KITAPADI>
<KITAPADI>Öteki Renkler</KITAPADI>
...

DEĞER ÜRETEN XPATH İŞLEVLERİ

Düğüm (öğe) kümesi oluşturmak dışında XPath'in değer üreten işlevleri de vardır. Tabii DOM bileşeninin SelectNodes işlevinde bunlar işe yaramaz. Zira, SelectNodes için, süzme yapılabilecek bir sorgu metni kullanmak gerekir.

Yukarıda da belirttiğimiz üzere XSL'deki value-of, for-each gibi belli komutlarda XPath deyimleri kullanılabilir. Önceki yazılarımızda işlediğimiz şablonlar konusunda XPath'ten az da olsa faydalanmıştık. Aşağıdaki XSL örneğinin tüm kitaplara ait yazar bilgilerini listelediğini, kursumuzun önceki derslerinden edindiğiniz bilgilere göre anlamaya çalışın:

<?xml version="1.0" encoding="ISO-8859-9"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:template match="/">

<h1>Kitaplar</h1>

<xsl:for-each select="/KITAPLAR/KITAP">
  <xsl:value-of select="YAZAR"/><br/>
</xsl:for-each>

</xsl:template>

</xsl:stylesheet>

Yukarıdaki XSL belgesi aşağıdaki çıktıyı üretecektir:

<H1>Kitaplar<H1>
Alptekin Dursunoğlu<br>
Ahmet Altan<br>
Buket Uzuner<br>
George Orwell<br>
Orhan Pamuk<br>
...

Yine önceki yazılarda bahsettiğimiz position() işlevinin bir sıra numarası ürettiğini tekrarlayalım. Yukarıdaki for-each bölgesini aşağıdaki şekilde değiştirdiğimizde çıktıda sıra numaraları da yer alacaktır.

<xsl:for-each select="/KITAPLAR/KITAP">
  <xsl:value-of select="position()"/><br/>
  <xsl:value-of select="YAZAR"/><br/>
</xsl:for-each>

 
1) Alptekin Dursunoğlu<br>
2) Ahmet Altan<br>
3) Buket Uzuner<br>
4) George Orwell<br>
5) Orhan Pamuk<br>
...

 
Buradaki postion() deyimi aslında XPath'te mevcut işlevlerden biridir. Yukarıda DOM'un SelectNodes işlevini incelerken sıra numarası belirtmek için köşeli parantezler içinde bir sayı kullanmıştık. /KITAPLAR/KITAP[2] gibi. Bu deyimde aslında position() işlevinden faydalanılmaktadır ve deyimin gerçek karşılığı gerçekte aşağıdaki şekildedir:

/KITAPLAR/KITAP[position() = 2]

Position() bir değer ürettiği için, örnekte olduğu gibi bunu xsl:value-of ile yazdırmak olanaklıdır.

Position() işlevi, gelişmiş sorgular hazırlamak için de kullanılabiliyor. Sıra numarasını kısıtlamak gerektiği durumlarda aşağıdaki gibi bir deyim yazılabilir.

//KITAP[position()<=5]/YAYINEVI

Bu deyimle birlikte yalnızca ilk 5 kitabın yayınevi bilgisi listelenecektir.

<YAYINEVI>Anka</YAYINEVI>
<YAYINEVI>Can</YAYINEVI>
<YAYINEVI>Remzi</YAYINEVI>
<YAYINEVI>MEB</YAYINEVI>
<YAYINEVI>İletişim</YAYINEVI>


XPATH İŞLEVLERİ

Position dışında XPath'te temel birkaç işlev daha vardır. Contains() ve Starts-with() bunlardan ikisidir. Contains işlevi bir metnin başka bir metin içinde olup olmadığını araştırır. Starts-with ise ana metnin, ikinci metin ile başlayıp başlamadığını kontrol eder.

Bu iki işlev değerler içinde arama yapar ve sonucun doğru olup olmadığını ifade eden iki değerli bir doğru-yanlış (boolean) değeri döndürür. Value-of ile kullanıldığında bu değerler ekrana yazdırılır. SelectNodes ya da For-each benzeri bir deyimde kullanıldığında ise düğüm kümesi elde edilir.

Aşağıdaki iki örnek bunu iyi açıklamaktadır:

<xsl:for-each select="/KITAPLAR/KITAP"> 
  <xsl:value-of select="starts-with(YAZAR,'Orhan')" /><br/> 
</xsl:for-each> 

Bu döngünün sonucu false ya da true içeren uzun bir listedir. Her kitap için yazar bilgisi araştırılmıştır ve "Orhan" ile başlayanlar için "true", diğerleri için "false" değeri yazdırılmıştır.

Şu örnekte yazarının adında "Pamuk" geçen kitapların adları listeleniyor.

<xsl:for-each select="/KITAPLAR/KITAP[contains(YAZAR,'Pamuk')]">
  <xsl:value-of select="KITAPADI" /><br/>
</xsl:for-each>

DOM'un SelectNodes işlevinde bunun karşılığı aşağıdaki gibidir:

  DOMDocument.SelectNodes("/KITAPLAR/KITAP[contains(YAZAR,'Pamuk')]")

SelectNodes'teki ifade ile For-each Select'teki ifadenin aynı olduğuna dikkat edin.


XPATH DÜZENLEYİCİ

XPath ile çalışırken deyimleri denemek için hazırladığımız Chip XPath Düzenleyici adlı küçük HTML uygulamasını bu ay CD'mizde sunuyoruz. Uygulama ile, girilen XML bilgisinden belirtilen koşullara göre süzme yapılabiliyor. Ekteki kitaplar.xml dosyası da alındığı takdirde bu dosya geçerli olarak sayfadaki XML kutusuna yükleniyor.

Siz Chip XPath Düzenleyici ile denemeler yapıyorken, biz gelecek ay için XPath'i daha ayrıntılı olarak ele alacağımız dersimizi hazırlıyor olacağız.
 

DOSYALAR:
kitaplar.xml
kitaplar.xsl
XPath Düzenleyici

 
Serkan ŞAHİNOĞLU
(Chip Dergisi, Ekim 2002)


http://BilgiTeknoloji.net