Monday, April 29, 2013

Java 7 ile gelen Böl-Katıl Çatısının Başarım Analizi

Geliştirdiğimiz uygulamaların yüksek başarımla çalışması hepimizin arzu ettiği bir durum. Ancak bu her zaman ulaşılması kolay bir hedef olmayabilir. Özellikle günümüzde yazılımdan beklentilerin sürekli arttığı göz önüne alındığında. Başarımı iyileştirmeyi mutlaka yazılım geliştirme sürecinin (müşteriden isteklerin alınması, sistem çözümleme, detaylı tasarım, mimari tasarım, gerçekleme, sınama, bakım) bir parçası haline getirmeliyiz. Başarımı en iyilemek yazılım ortaya çıktıktan sonra yapılan bir etkinlik olmamalı. Java uygulamalarının başarımının en iyilenmesi ise farklı katmanlarda çalışmayı gerektirir. Donanım katmanı, İşletim sistemi katmanı, Java Sanal Makinası (JSM) katmanı ve elbette uygulama katmanı. Burada yer alan her bir katmandaki başarımı artırmak için ne yazık ki elimizde sihirli bir değnek bulunmuyor. Donanım katmanındaki gelişmeler elimizi güçlendiriyor: Çok çekirdekli  mimariler, büyük bellekli bilgisayar sistemleri, daha yüksek kapasiteli cep bellekler (L0, L1, L2, L3), katı hal diskler, daha hızlı ara bağlaşım birimleri, çok çekirdekli yüksek başarımlı ekran kartı işlemcileri. İşletim sistemleri bu donanım kaynaklarını uygulamalar ve kullanıcılar arasında verimli bir şekilde dağıtmaktan ve yönetmekten sorumlu çok sayıda servisten oluşuyor: proses sıralayıcı, sanal bellek yönetimi, giriş/çıkış yönetimi, kullanıcı yönetimi, dosya sistemi, pencereleme sistemi. Linux (Red Hat, Suse), Unix (Oracle Solaris, IBM AIX, HP-UX), Microsoft Windows gibi işletim sistemleri bu güncel sistem kaynaklarını iyi yönettikleri söylenebilir. Yine de genel amaçlı işletim sistemi olmalarından kaynaklanan bazı darboğazlar yaşıyorlar. 
Java uygulamaları doğrudan işletim sistemi üzerinde çalışmazlar. Bir sanal makinaya ihtiyaç duyarlar: Java Sanal Makinası (JSM). JSM'nin görevi, kabaca, Java uygulamalarını oluşturan bytecode olarak isimlendirilen makina komutlarını, üzerinde çalıştığı işletim sisteminin ve işlemcinin anlayacağı ve çalıştırabileceği forma çevirmektir. Java platformunun en güçlü tarafının JSM olduğu söylenebilir. JSM bu dönüşümü yaparken devingen en iyileme yapabilmektedir. C/C++'da kod yazdığınızda ise derleyici ancak durağan en iyileme yapabilir. Durağan en iyileme ise başarımda kısıtlı bir iyileşme sağlayabilir. JSM içinde başarımı belirlemede önemli işlevi olan iki bileşen yer alır: Tam Anında Derleme ve Çöp Toplayıcı. Java uygulamaları çalışmaya başladıklarında yorumlamalı olarak çalışırlar. JSM uygulamayı çalıştırırken kesitini de alır. Eğer bir iyileştirme görüyorsa sınıf metotlarını bytecode'dan işlemcinin doğrudan çalıştırabileceği doğal komutlara dönüştürür.
JSM satın alabileceğiniz, üretebileceğiniz bir işlemci tanımlar. Bu işlemcinin bir komut kümesi, yığın temelli adresleme kipleri, saklayıcı kümesi, yığın göstergesi, program sayacı, bellek modeli vardır. Çoğu zaman JSM'yi yazılımsal olarak ediniriz. Oracle, hemen hemen tüm işletim sistemleri için bir JSM yayınlıyor. Bu adresten elinizdeki işletim sistemi için bir JRE ya da JDK indirebilirsiniz. Eğer amacınız sadece Java uygulamalarını çalıştırmak ise Java Runtime Environment (JRE) yeterli olacaktır. Eğer uygulama geliştirmek isterseniz Java Geliştirme Çantasını (Java Development Kit, JDK) indirmeniz gerekir. Şu an Javanın 7 sürümü var. 2014 yılında 8 sürümünün çıkmasını bekliyoruz. Her yeni sürümde dilde bazı eklentiler, mevcut API'lerde değişiklikler ve yeni API'ler ile tanışıyoruz. Bu arada yeni sürümlerde bazen JSM'de de değişiklikler olabiliyor. Şu ana kadar ki yeni sürümlerde Java 1.2 ve Java SE 5'de dilde ciddi sayılabilecek yenilik geldi. Java 7 ile dilde gelen yenilikler daha çok geliştiricinin kodlama başarımını iyileştiren türden. Ancak Java 7'de JSM'de başarımı artırabilecek bazı gelişmeler de var:

  1. Sınıf yükleyici artık çok iş parçacıklı. Bu sınıfların eş zamanlı olarak yüklenebilmesine olanak sağlıyor. Böylelikle çok parçacıklı uygulamaların açılış zamanı başarımı bir miktar iyileştirecektir. 
  2. invokedynamic. Uzun bir aradan sonra JSM yeni bir komuta kavuştu. Bu daha çok özellikle dinamik tipli dillerin JSM üzerinde doğal olarak çalışabilmesini amaçlıyor. Dinamik tipli diller ile yazılan uygulamalar Java 6'da Scripting API (JSR 223) aracılığı ile zaten çalıştırılabiliyordu. Ancak bu Reflection API ile sağlandığından yavaştı. Şimdi Ruby gibi dillerle yazılan uygulamaların JSM üzerinde Scripting API gibi ara bir çözüme ya da katmana ihtiyaç duymadan doğal olarak ve yüksek başarımla çalışmasını bekliyoruz.
  3. -XX:-TieredCompilation: JSM içinde iki tür tam anında derleyici bulunur: Sunucu tipi ve İstemci tipi. JSM sunucu tipinde ise derleyici uygulamanın birim zamanda daha çok iş çıkarmasını sağlayacak şekilde davranır ve daha çok en iyileme seçeneği açıktır. JSM istemci tipinde ise tam anında derleyici, uygulamanın açılış zamanını iyileştirecek şekilde davranır. Java 7 ile gelen TieredCompilation seçeneğinde ise sunucu ve istemci tipindeki JSM'lerin iyi özelliklerinin birleştirilmeye çalışıldığını görüyoruz.
  4. -XX:+UseG1GC: Java 7'de yeni bir çöp toplayıcımız var: Garbage First (G1). G1 artımsal, paralel, kuşaklara dayalı, eş zamanlı, uygulamanın tüm iş parçacıklarını durdurduğu bir fazı olan bir çöp toplayıcı. Java 6 v öncesindeki (Mostly) Concurrent Mark-Sweep (CMS) yerini alması amaçlanıyor. CMS'ye göre iki önemli üstünlüğü bulunuyor: i) parçalanma oluşmuyor ii) çöp toplama ve duraksatma süresi için bir üst sınır verilebiliniyor. CMS ile G1 karşılaştırması ve G1'in detayları için bu sunumu okuyabilirsiniz.
  5. Çok çekirdekli mimariler üzerinde programlama: Java 7 Böl/Katıl çatısı olarak adlandırılan çok çekirdekli sistemlerde uygulama geliştirmek için bir çözüm sunuyor. Bu çözüm, Concurrency API ile gelen yeni bir iş parçası havuzu olan ForkJoinPool ve bu havuza atayacağımız iş parçacıklarını tanımladığımız RecursiveAction ve RecursiveTask sınıflarını kullanmaktadır. 
Bu yazıda Böl/Katıl çatısının çekirdek sayısına göre ölçeklenebilirliğini inceleyeceğiz. Örnek uygulama olarak görüntü işlemede kullanılan bulanıklaştırma işlemini seçtim. Kod aşağıda listelenmiştir:
1:  package com.example.forkjoin;  
2:  import com.example.util.ImageFrame;  
3:  import java.awt.image.*;  
4:  import java.io.*;  
5:  import java.util.concurrent.*;  
6:  import javax.imageio.*;  
7:  public class ForkBlur extends RecursiveAction {  
8:    protected static int BENCHMARK_LOOP_SIZE = 10;  
9:    protected static int SERIAL_THRESHOLD = 10_000;  
10:    private final int[] mSource;  
11:    private final int mStart;  
12:    private final int mLength;  
13:    private final int[] mDestination;  
14:    private int mBlurWidth = 15;  
15:    public ForkBlur(int[] src, int start, int length, int[] dst) {  
16:      mSource = src;  
17:      mStart = start;  
18:      mLength = length;  
19:      mDestination = dst;  
20:    }  
21:    protected void serialComputation() {  
22:      int sidePixels = (mBlurWidth - 1) / 2;  
23:      for (int index = mStart; index < mStart + mLength; index++) {  
24:        // Calculate the average.  
25:        float rt = 0, gt = 0, bt = 0;  
26:        for (int mi = -sidePixels; mi <= sidePixels; mi++) {  
27:          int mindex = Math.min(Math.max(mi + index, 0), mSource.length - 1);  
28:          int pixel = mSource[mindex];  
29:          rt += (float) ((pixel & 0x00ff0000) >> 16);  
30:          gt += (float) ((pixel & 0x0000ff00) >> 8);  
31:          bt += (float) (pixel & 0x000000ff);  
32:        }  
33:        rt = rt / mBlurWidth;  
34:        gt = gt / mBlurWidth;  
35:        bt = bt / mBlurWidth;  
36:        int dpixel = (0xff000000)  
37:            | (((int) rt) << 16)  
38:            | (((int) gt) << 8)  
39:            | ((int) bt);  
40:        mDestination[index] = dpixel;  
41:      }  
42:    }  
43:    @Override  
44:    protected void compute() {  
45:      if (mLength < SERIAL_THRESHOLD) {  
46:        serialComputation();  
47:        return;  
48:      }  
49:      int split = mLength / 2;  
50:      invokeAll(new ForkBlur(mSource, mStart, split, mDestination),  
51:          new ForkBlur(mSource, mStart + split, mLength - split, mDestination));  
52:    }  
53:    public static BufferedImage blur(BufferedImage srcImage,int blurWidth) {  
54:      int w = srcImage.getWidth();  
55:      int h = srcImage.getHeight();  
56:      int[] src = srcImage.getRGB(0, 0, w, h, null, 0, w);  
57:      int[] dst = new int[src.length];  
58:      ForkBlur fb = new ForkBlur(src, 0, src.length, dst);  
59:      fb.setBlurWidth(blurWidth);  
60:      ForkJoinPool pool = new ForkJoinPool();  
61:      long startTime = System.currentTimeMillis();  
62:      pool.invoke(fb);  
63:      long endTime = System.currentTimeMillis();  
64:      System.err.println("Image blur took " + (endTime - startTime) + " milliseconds.");  
65:      BufferedImage dstImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);  
66:      dstImage.setRGB(0, 0, w, h, dst, 0, w);  
67:      return dstImage;  
68:    }  
69:    public int getBlurWidth() {  
70:      return mBlurWidth;  
71:    }  
72:    public void setBlurWidth(int mBlurWidth) {  
73:      this.mBlurWidth = mBlurWidth;  
74:    }  
75:    public static void main(String[] args) throws Exception {  
76:      String filename = "src/red-tulips.jpg";  
77:      File file = new File(filename);  
78:      BufferedImage image = ImageIO.read(file);  
79:      BufferedImage blurredImage = null;  
80:      int processors = Runtime.getRuntime().availableProcessors();  
81:      System.err.println(Integer.toString(processors) + " processor"  
82:          + (processors != 1 ? "s are " : " is ")  
83:          + "available");  
84:      for (int k = 15; k < 64; k += 2) {  
85:        for (int j = 1; j <= 10; ++j) {  
86:          System.err.println("Threshold is " + SERIAL_THRESHOLD);  
87:          SERIAL_THRESHOLD = 1_000 * j;  
88:          for (int i = 0; i < BENCHMARK_LOOP_SIZE; ++i) {  
89:            blurredImage = blur(image,k);  
90:            System.gc();  
91:          }  
92:        }  
93:        SERIAL_THRESHOLD = 100_000_000;  
94:        for (int i = 0; i < BENCHMARK_LOOP_SIZE; ++i) {  
95:          blurredImage = blur(image,k);  
96:          System.gc();  
97:        }  
98:      }  
99:    }  
100:  }  

Problemi seri olarak çözmekle parçalamak arasındaki kararı SERIAL_THRESHOLD ile veriyoruz. Denemelerde SERIAL_THRESHOLD sabitinin değeri 10,000 olarak kullanılmıştır. Farklı boyutlarda bulanıklaştırma süzgeci kullanılmıştır. Böl/Katıl çatısı ve seri çözümlerin süzgeç boyutuna göre süzgeçleme süresi ve hızlanma aşağıdaki şekillerde gösterilmiştir:



Test olarak kullanılan imge aşağıda verilmiştir. İmge altı milyon (3,000x2,000) benekten oluşmaktadır.  Böl ve katıl çatısında problemi seri olarak çözmek daha etkin oluncaya kadar   bölmeye devam ediyoruz. Burada seri olarak çözme kararı için bir eşik değeri (SERIAL_THRESHOLD) kullanıyoruz. Eğer benek sayısı 10,000'in altında ise seri olarak çözmeye karar veriyoruz:
45:      if (mLength < SERIAL_THRESHOLD) {  
46:        serialComputation();  
47:        return;  

Buna göre elimizdeki test imgesi için 600 görev oluşacaktır. Bu görevler Java 7 ile gelen ForkJoinPool havuzundaki çekirdek sayısı kadar iş parçacığı tarafından çalıştırılacaktır. Testlerde 8 çekirdekli bir makina kullanılmıştır. Dolayısı ile havuzda 8 iş parçacığı bulunmaktadır. Bu iş parçacıklarının özelliği her birinin bir çekirdeğe bağlanmış olmasıdır.

Hızlanma oranı, süzgecin boyutu arttıkça işlemci sayısına yaklaştığı görülmektedir. Seri çözümde, katlama süresi süzgeç boyutu ile doğrusal bir şekilde artarken, Böl/Katıl çatısı ile Java 7'de oluşturulan çözümde ise neredeyse sabit kalmaktadır. Uygulamanın kaynak kodunu NetBeans 7 projesi olarak bu adresten indirebilirsiniz.




Tuesday, April 23, 2013

Java 8'in Çıkışı [Şimdilik] Mart 2014'e Ertelendi

Java 8'in Eylül 2013 tarihinde çıkması planlanıyordu. Bu tarihe yetiştirebilmek için bazı önemli özellikler (örneğin Project JigsawJava 9'a bırakılmıştı. Bu haliyle bile Java 8'in eylül ayına yetişmeyeceği duyuruldu. Mark Reinhold'un yeni önerdiği plan Mart 2014'ü işaret ediyor. 
Open JDK 8 sayfasında yeni plan aşağıdaki gibi değiştirilmiş durumda:
2012/04/26M1
2012/06/14M2
2012/08/02M3
2012/09/13M4
2012/11/29M5
2013/01/31M6
2013/05/23M7Feature Complete
2013/09/05M8Developer Preview
2014/01/23M9Final Release Candidate
2014/03/18GAGeneral Availability


Oracle bir kez daha hayal kırıklığı yaratıyor: 
Date: Thu, 18 Apr 2013 09:28:11 -0700
From: mark.reinhold@oracle.com
Subject: Proposed new schedule for JDK 8
To: jdk8-dev@openjdk.java.net
Message-ID: <20130418092811.584942@eggemoggin.niobe.net>
Content-Type: text/plain; charset=us-ascii

As I wrote earlier today on my blog [1], the Java 8 schedule is no longer
achievable due to a renewed focus on security on the part of all of us
here at Oracle.

There are many options for how to proceed from here, some of which I
discuss in the blog entry.  As I've written previously [2], the most
important JEPs that we've slipped into M7 are related to Project Lambda,
the sole driving feature of the release.  Our current estimate is that we
can finish the remaining work on Lambda by early May, about three months
later than planned.  The other M7 JEPs are not release drivers, so in
theory we could just drop them from the release, but if Lambda needs
more time then there's no point in doing that.

With all that in mind, I think the least-bad option is to slip the
schedule just enough to finish Lambda.

Here, then, is a proposed new schedule for JDK 8:

  2013/05/09  M7  Feature Complete
  2013/07/18      Rampdown start
  2013/09/05  M8  Developer Preview
  2013/09/12      All Tests Run
  2013/10/10      API/Interface Freeze
  2013/10/24      Zero Bug Bounce
  2013/11/21      Rampdown phase 2
  2014/01/23  M9  Final Release Candidate
  2014/03/18  GA  General Availability
A final release in March of 2014 is, of course, more than three months
later than the current GA date in early September.  At this point we're
not confident that we could be ready for a GA release in November, and
experience has shown that it's almost always a bad idea to try to ship a
major software release in December, so that pushes the GA date well into
the first quarter.

The intent here is not to open the gates for a flood of new features, nor
to permit the scope of existing features to grow without bound.  We'd
likely propose a select few additional features, especially in areas
related to security.  In general, however, we'd use the additional time
to stabilize, polish, and fine-tune the features that we already have
rather than add a bunch of new ones.

Is this the best possible course of action?  I think it's better than the
alternatives, but I'm open to suggestions.  I'd like to hear from other
contributors to this Project, especially those involved in efforts to use
the JDK 8 code base to build binary distributions that are expected to
see wide use.

Please let me know your thoughts by this time next week.  In the meantime
I'll post the above proposed schedule to the JDK 8 Project page [3] for
reference.

- Mark


[1] http://mreinhold.org/blog/secure-the-train
[2] http://mail.openjdk.java.net/pipermail/jdk8-dev/2013-February/002066.html
[3] http://openjdk.java.net/projects/jdk8/

Monday, April 22, 2013

Oracle 11gR2'de C Fonksiyonlarının PL/SQL Fonksiyonu/Yordamı olarak Kullanımı

Oracle veritabanı üzerinde, sunucu tarafta uygulama geliştirmek için PL/SQL kullanıyoruz. PL/SQL,  yapısal sorgulama diline (SQL) programlama yeteneği kazandırmaktadır. PL/SQL, fonksiyon ve yordam tanımlamak, paket oluşturmak, kendi veri tipimizi tanımlamak, döngü ve akış denetimi gibi programlamaya ilişkin tüm yapıları barındırıyor. Ancak bazen daha karmışık algoritmaları C'de ya da Java programlama dillerinde çözümlerini oluşturmak zorunda kalabiliyoruz. Bazen de daha önce C'de ya da Java'da geliştirdiğimiz bir fonksiyonu PL/SQL'de yeniden gerçeklemek ile zaman kaybetmeden kullanmak isteriz. Bu durumda ilk olarak fonsiyonunun yer aldığı kütüphaneyi Oracle veritabanı yönetim sistemine tanıtmamız gerekir:
 CREATE OR REPLACE LIBRARY funlib as '$ORACLE_HOME/bin/libfun.so';  
Burada $ORACLE_HOME isimli sistem değişkeni oracle veritabanının kurulu olduğu dizini ifade ediyor. Benim makinamda bu değişken /u01/app/oracle/product/11.2.0/dbhome_1 dizinini gösteriyor. CREATE LIBRARY komutunu çalıştırabilmek için kullanıcının bu yetkiye sahip olması gerekir. Bu yetkiyi aşağıdaki gibi bir GRANT komutu ile tanımlayabiliriz:
 GRANT CREATE LIBRARY , RESOURCE to fundb ;  
Şimdi ise C'de örnek kütüphane oluşturalım. Burada öncelikle bir başlık dosyası oluşturalım.
fun.h
 #ifndef __fun__  
 #define __fun__  
   int havefun(int);  
   double l1_norm(double *,double *,int);  
 #endif  
Ardından gerçeklemeyi c dosyasında yapıyoruz:
fun.c
1:   #include "fun.h"   
2:   #include <stdlib.h>   
3:   #include <math.h>   
4:   double l1_norm(double *fv1,double *fv2,int size){   
5:    double l1_distance=0;   
6:    int i=0;   
7:    for (i=0;i<size;++i){   
8:     l1_distance += fabs(fv1[i]-fv2[2]);   
9:    }   
10:    return 1.0 / (1.0 + exp(-l1_distance));   
11:   }   
12:   int havefun(int n){   
13:    int len=1;   
14:    if (n<=1) return len;   
15:    while (n>1){   
16:     if (n%2 == 0) n=n/2;   
17:     else n=3*n+1;   
18:     len++;   
19:    }   
20:    return len;   
21:   }   
Paylaşılan kütüphane dosyasını oluşturmak için GNU C derleyecisi ile aşağıdaki gibi derliyoruz:
 gcc -fPIC -shared -o libfun.so fun.c  
Eğer 64-bitlik bir işletim sisteminde Oracle veritabanını kullanıyorsanız derleyiciye -m64 seçeneğini de vermeniz gerekir.
Şimdi PL/SQL'de kullanıcı tanımlı fonksiyon tanımlayacağız ve bunu yaparken PL/SQL fonksiyonunu libfun.so'da tanımlı C fonksiyonları ile eşleştireceğiz:
 CREATE OR REPLACE FUNCTION l1dist (  
  fv1 FEATURE_VECTOR, fv2 FEATURE_VECTOR , sz BINARY_INTEGER )  
   RETURN NUMBER  
   AS LANGUAGE C  
   LIBRARY mylib  
   NAME "l1norm" ;  
 CREATE OR REPLACE FUNCTION havefun ( num BINARY_INTEGER )  
  RETURN BINARY_INTEGER  
  AS LANGUAGE C  
  LIBRARY mylib  
  NAME "havefun" ;  
Tanımda gözüken FEATURE_VECTOR tipini ise daha önce aşağıdaki gibi tanımlamanız gerekir:
 CREATE OR REPLACE TYPE FEATURE_VECTOR IS VARRAY(2952) OF NUMBER;  
Artık havefun fonksiyonunu sınayabiliriz:

SQL> select havefun(7) from dual;
HAVEFUN(7)
---------- 17

Tuesday, April 16, 2013

Çok Sunuculu MySQL Mimarilerinde Yük Dengeleme Çözümleri

Giriş

Kurumsal uygulamaların her zaman erişilebilir ve ölçeklenebilir olmasını istiyoruz. Bunun için bilişim sistemini oluşturan her katmanda bu özellikleri sağlamamız gerekir. Bu katmanlardan biri de verileri kalıcı olarak saklamamızı ve gerektiğinde olabildiğince hızlı bir şekilde erişmemizi sağlayan ilişkisel veri tabanı sistemleridir. MySQL açık kaynak kodlu, (Oracle, MariaDB, Percona gibi) firmalardan desteğini alabileceğiniz, yaygın ve çok ölçekli kullanımı olan (Facebook gibi) bir çözüm olarak öne çıkmaktadır. MySQL'de çok sunuculu sistemler kurmak mümkündür. Çok sunuculu sistemler, yineleme (=replication) ya da MySQL kümesi (=cluster) ile kurulabilinir. Her birinin kendine göre kazanımları ve yitimleri bulunmaktadır. Bu yazının konusu, bu tür çok sunuculu MySQL sistemlerine istemcilerden ya da uygulamalardan erişimin yükü dengeleyecek şekilde nasıl sağlanabileceğidir. Bunu temel olarak iki şekilde sağlıyoruz:
  1. MySQL Proxy sunucusunu kullanmak
  2. Eğer uygulamalar Java uygulaması ise Connector/J JDBC sürücüsü kullanmak 
Birinci bölümde MySQL Proxy ve ikinci bölümde ise Connector/J çözümlerini sırayla inceleyeceğiz.

I. MySQL Proxy Kullanımı

İlk çözüm, MySQL sunucularına erişimde, istemci ile sunucu arasında vekil sunucu olarak adlandırdığımız MySQL Proxy sunucusu kullanmaktır. Vekil sunucuya çoğunlukla uygulamaların veritabanına erişiminin günlüğünü tutmak, istemcilerin yaptığı işlemlerin güvenlik amacıyla kaydını tutumak, uygulamanın başarımını ölçmek gibi görevler yükleriz. Asıl işi MySQL sunucusu yapmaktadır. Vekil sunucusu temel olarak istemcilerden gelen istekleri sunucuya yönlendirir. Bunu yaparken kendisine yüklenen sorumluluğu da yerine getirir. Vekile yük dengeleme görevi de verilebilinir. MySQL Proxy'nin en güncel sürümü 0.8.3 alpha'dır ve bu bağlantıdan indirebilirsiniz. Bu sürüm MySQL 5.0 ve sonrasındaki tüm sunucularla çalışmaktadır. 
MySQL Proxy içinden hazır olarak yük dengeleme betiği çıkmaktadır. MySQL Proxy programlama dili olarak lua'yı kullanır. Dolayısı ile yeni görevler vermek isterseniz lua dilini kullanarak kod yazmanız gerekir.
Kurulumu yaptığımızda kurulum dizininde aşağıdaki dizinler yer almaktadır:

01/15/2013  03:19 PM    <DIR>          bin
08/06/2012  01:42 PM            18,092 COPYING.txt
01/15/2013  03:19 PM    <DIR>          include
01/15/2013  03:19 PM    <DIR>          lib
01/15/2013  03:19 PM    <DIR>          licenses
08/06/2012  01:42 PM            75,713 README.txt
01/15/2013  03:19 PM    <DIR>          share
Burada bin dizininde vekil sunucusunu çalıştırmamızı sağlayacak uygulama yer alır: mysql-proxy. share\doc\mysql-proxy dizininde ise hazır kullabileceğimiz lua betikleri yer alıyor:

Directory of c:\opt32\mysql-proxy-0.8.3\share\doc\mysql-proxy

active-queries.lua        active-transactions.lua   admin-sql.lua
analyze-query.lua         auditing.lua              commit-obfuscator.lua
histogram.lua             load-multi.lua            ro-balance.lua
ro-pooling.lua            rw-splitting.lua          tutorial-basic.lua
tutorial-constants.lua    tutorial-inject.lua       tutorial-keepalive.lua
tutorial-monitor.lua      tutorial-packets.lua      tutorial-prep-stmts.lua
tutorial-query-time.lua   tutorial-resultset.lua    tutorial-rewrite.lua
tutorial-routing.lua      tutorial-scramble.lua     tutorial-states.lua
tutorial-tokenize.lua     tutorial-union.lua        tutorial-warnings.lua
xtab.lua

Proxy sunucusunu başlatmak için mysql-proxy.exe uygulamasını başlatmak gerekiyor:

cmd> mysql-proxy.exe --daemon --proxy-backend-addresses=192.168.1.1:3306 --proxy-read-only-backend-addresses=192.168.1.2:3306 --proxy-read-only-backend-addresses=192.168.1.3:3306 --proxy-lua-
script=c:\opt32\mysql-proxy-0.8.3\share\doc\mysql-proxy\rw-splitting.lua
2012-04-15 15:47:40: (critical) plugin proxy 0.8.3 started

Bu örnekte bir usta ve iki yamak MySQL sunucusunun olduğu yineleme mimarisi kullanılmıştır. Usta 192.168.1.1 nolu IP adresini, yamaklar ise 192.168.1.2 ve 192.168.1.3 nolu IP adreslerini dinlemektedir. İstemcilerinden gelen SELECT cümlelerini yamaklara ve INSERT/UPDATE/DELETE isteklerini ise ustaya yönlendiren betik rw-splitting.lua isimli dosyada yer almaktadır. Ustanın IP adresini proxy-backend-addresses parametresi ile yamakların IP adresini ise proxy-read-only-backend-addresseparametresi ile veriyoruz. MySQL Proxy 4400 numaralı portta çalışmaktadır. Şimdi sunucuya MySQL istemcisi üzerinden erişebiliriz:

cmd> mysql -uroot -proot --port 4040
Warning: Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.6.10-log MySQL Community Server (GPL)
Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> status
--------------
mysql  Ver 14.14 Distrib 5.6.10, for Win32 (x86)
Connection id:          3
Current database:       world
Current user:           root@localhost
SSL:                    Not in use
Using delimiter:        ;
Server version:         5.6.10-log MySQL Community Server (GPL)
Protocol version:       10
Connection:             localhost via TCP/IP
Server characterset:    latin1
Db     characterset:    latin1
Client characterset:    cp850
Conn.  characterset:    cp850
TCP port:               4040
Uptime:                 9 min 24 sec
Threads: 3  Questions: 18  Slow queries: 0  Opens: 70  Flush tables: 1  Open tab
les: 63  Queries per second avg: 0.031
--------------

Proxy sunucusunun SELECT cümlelerini gerçekten yamaklara gönderdiğini test etmek için Sorgu cebini açıp izleyebilirsiniz:

mysql> show status like 'Qcac%';
+-------------------------+---------+
| Variable_name           | Value   |
+-------------------------+---------+
| Qcache_free_blocks      | 1       |
| Qcache_free_memory      | 1031288 |
| Qcache_hits             | 14      |
| Qcache_inserts          | 5       |
| Qcache_lowmem_prunes    | 0       |
| Qcache_not_cached       | 11      |
| Qcache_queries_in_cache | 4       |
| Qcache_total_blocks     | 10      |
+-------------------------+---------+
8 rows in set (0.00 sec)

II. Connector/J Kullanımı

MySQL sunucuna Java uygulamasından bağlanabilmek için JDBC sürücüsü kullanıyoruz. MySQL bize Connector/J ile bu sürücüyü sağlıyor. Bu sürücünün yeteneklerinden biri de yük dengeleme yapabilmesidir. Üstelik sunucuları dinamik olarak eklemek çıkarılabilmek mümkündür. Sunucuların listesini, JDBC URL tanımında virgüllerle ayırarak veriyoruz:
jdbc:mysql:loadbalance://192.168.1.1:3306,192.168.1.2:3306,192.168.1.3:3306/world
Bu özelliğin kullanıldığı örnek uygulama kodunu aşağıda bulabilirsiniz:
1:  package com.example.test;  
2:  import java.sql.*;  
3:  /**  
4:   *  
5:   * @author Binnur Kurt  
6:   */  
7:  public class TestConnector {  
8:   public static void main(String[] args)   
9:      throws ClassNotFoundException,SQLException,InterruptedException {  
10:    Class.forName("com.mysql.jdbc.Driver");  
11:    int i = 0;  
12:    while (i < 1000) {  
13:     Connection connection = DriverManager.getConnection(  
14:      "jdbc:mysql:loadbalance://192.168.1.1:3306,192.168.1.2:3306, "+  
15:      "192.168.1.3:3306/world?"+  
16:       "loadBalanceConnectionGroup=first&loadBalanceEnableJMX=true",  
17:      "root", "root");  
18:    Statement statement = connection.createStatement();  
19:    ResultSet rs = statement.executeQuery("SELECT * FROM Country limit 10");  
20:    while (rs.next()) {  
21:      String code = rs.getString("Code");  
22:      String name = rs.getString("Name");  
23:      long population = rs.getLong("Population");  
24:      System.err.println(name + "\t" + code + "\t" + population);  
25:    }  
26:    rs.close();  
27:    connection.close();  
28:    Thread.sleep(5000);  
29:    ++i;  
30:   }  
31:   }  
32:  }  
jconsole ile uygulamaya bağlanıp com.mysql.jdbc.jmx'de tanımlı MBean'leri kullanarak yürütme zamanında yeni sunucular eklemek veya sunucu çıkarmak mümkün olabilmektedir:

Monday, April 15, 2013

XML Belgeleri XSL ve XPath Kullanarak Dönüştürmek

Uygulamalar arasında sorunsuz veri alış-verişi için kullanılabilecek en uygun teknoloji XML'dir. XML'de veriyi, verinin ne anlama geldiğini tanımlayan meta-veri olarak adlandırılan verilerle birlikte kodluyoruz. Web servisleri kurumsal uygulamaların tümleştirilmesi için en hızlı ve ucuz çözümdür. Web servisleri bunu, uygulamanın fonksiyonlarını ve verilerini, platformdan bağımsız bir şekilde paylaştırarak sağlar. Web servisleri XML tabanlı bir dizi teknoloji üzerine kuruludur:
  • Web Services Description Language: Web servisinin arayüzünün tanımlandığı, XML ve XML Schema teknolojileri kullanılarak oluşturulur. WSDL servisin tanımını iki bölüme ayırır:
    a)     Soyut arayüz:
    Soyut arayüz, servis tarafından desteklenen işlemler ve parametreleri, soyut veri tipleri gibi servise ilişkin genel özellikleri tanımlar. Bu tanımlamalar ağ adresi, ağ protokolü, veri gösterimi gibi bilgisayar ağ parametrelerinden tamamen bağımsızdır.
    b)    Somut gerçekleme:
    Gerçeklemeye ilişkin tanımlamalar, soyut arayüz tanımlarını gerçek ağ adresi, ağ protokolü ve gerçek veri tipleri ile eşleştirir. Hem soyut arayüz hem de somut gerçekleme tanımları XML elemanları aracılığı ile verilir. Sonuç olarak, WSDL dokümanı, http://schemas.xmlsoap.org/wsdl isim uzayında tanımlı XML Schema dokümanında tanımlı elemanlar kullanılarak oluşturulmuş bir XML dokümanıdır.
    Genel olarak bir WSDL dokümanının içeriği aşağıda verilmiştir.
             <definitions>
                   <types>
                       Soyut veri tipi tanımı
                   </types>
                   <message>
                        Servis giriş/çıkış parametrelerinin tanımları
                   </message>
                   <portType>
                        İskele (=port) tanımı
                    </portType>
                    <binding>
          Aynı iskeleye birden fazla iletişim protokolü üzerinden erişilebilinir. Bunun tanımı bu bölümde verilmektedir.
                    </binding>
                    <services>
                         Gerçeklemeye ilişkin tanımlar
                    </services>
             </definitions>

  • SOAP (=Simple Object Access Protocol): SOAP uygulamalar arasında yapısal ve tipli verilerin değişimi için geliştirilmiş XML tabanlı bir protokoldür. Web servis uygulamalarında üç çeşit aktör bulunmaktadır: servisi kullanan tüketici, servisi veren servis sağlayıcı ve servisin yerini söyleyen bir aracı. SOAP tüm bu aktörler arasındaki veri alış-verişine olanak sağlayan bir standarttır. Bu standart kesinlikle uygulamanın mantığı, iletişim protokolü, programlama modeli ya da programlama dili konusunda bir kısıt getirmez. Bunun yanında baştan beri genellikle HTTP üzerinden taşınmaktadır. Ama bunun yanında JMS, SMTP, SFTP gibi iletişim protokolleri üzerinden de taşınabilir.
  • UDDI (=Universal Description, Discovery and Integration): UDDI servis kayıtları Web servislerini kataloglama platformunu oluşturur. Web servis kayıt kataloğu merkezi bir Web servisi arama motorudur. Web servis istemcileri, bu arama motoru sayesinde, kendi amaçlarına uygun ve yeterli servis çözümlerini bulabilirler. Arama ölçütü erişim arayüzü gibi teknik bir konu olabileceği gibi servisin ticari ünü ve coğrafi konumu gibi teknik dışı konular da olabilir. Genel olarak UDDI kayıtlarında aşağıdaki bilgiler yer alır:
  • Web servisi sunan ticari firma ve kurumlar hakkında bilgiler
  • Firmaca sunulan Web servislerinin tanımını
  • Web servislerine erişim için gerekli arayüz ile ilgili teknik bilgiler
 Bunun yanında, UDDI, bu bilgilere erişim için Uygulama Yazılımı Arayüzü de sunar. Bu arayüz sayesinde Web istemcileri her zaman servis hakkında güncel bilgilere erişebilir. UDDI olgun bir teknoloji olmasına rağmen ağır sıklet bir teknoloji olduğu için pek kullanılmamaktadır. Bu teknolojinin yerini yine XML tabanlı bir teknoloji olan WSIL (Web Service Inspection Language) almıştır. XML web servisleri kurumsal uygulamaları biribirleri ile tümleştirmek ve Servis Odaklı Mimari çözümlerinde servisleri tanımlamak ya da gerçekleştirmek amacıyla yoğun olarak kullanılmaktadır.
XSL bir XML dokümanını bir başka XML dokümanına ya da başka bir tipte veriye (metin, xhtml, pdf, resim gibi) dönüştürmek için kullanılan bir XML tabanlı standarttır. Bu teknoloji iki temel bileşenden oluşmaktadır: XSLT ve XSL FO (Formatting Objects). XSLT XSL’in dönüşüm dilidir. XSLT’nin kendisi XML olarak kodlanmış bir dokümandır. Dolayısı ile XML dokümanlarının uyduğu tüm kurallara uyar. XML başlıklı konudan hatırlayacağınız gibi XML dokümanı bir ağaç tanımlar. XSLT bu ağacın herhangi bir bölümünün yeni bir dokümana nasıl dönüştürüleceğini tanımlar. Eğer çıkış bir XML dokümanı ise çıkış dokümanı bir başka ağaç olacaktır. Aşağıdaki şekilde tipik bir XSL uygulaması verilmiştir.

Bu uygulamada giriş her zaman bir XML dokümanı olmak zorundadır. XSLT işlemcisi giriş olarak aldığı XML dokümanını, dönüşümün nasıl olacağını tanımlayan XSLT dokümanı yardımı ile çıkış dokümanına dönüştürür. 
XSL'in diğer bileşeni ise XSL Biçimlendirme Nesneleridir (Formatting Objects). Özet olarak XSL’in XSLT, XPath ve XSL-FO’dan oluştuğunu söyleyebiliriz:
                     XSL=XSLT+XPath+XSL-FO
Aşağıdaki şekilde XSLT ve XSL-FO’nun kullanıldığı diğer bir uygulama türü verilmiştir. Burada XML dokümanı bir PDF dokümanına dönüştürülmektedir.
                
XSL’in elektronik ticaret açısından önemli bir teknolojidir. Farklı kurumlar benzer içerikler için kendi amaçlarına uygun XML dokümanları tasarlamış olabilirler. Bu durumda aynı içeriğin bir XML dosyadan diğerine kayıpsız ve hataya yol açmayacak şekilde dönüştürülmesi gerekir. Benzer şekilde içeriğin farklı amaçlarla sunulması gerekebilir. Bu durum özellikle içeriğin çok hızlı üretildiği ya da tüketildiği uygulamalarda önem kazanır. XSL elektronik ticaret uygulamaları ya da servisler için içerik ve sunumu tam olarak biri birinden ayırabilmesine olanak sağlar. XML içeriği kodlamak, XSL ise sunumu kodlamak için kullanılır. Aşağıdaki şekilde bir elektronik ticaret uygulaması için verilen örnekte, sipariş ile ilgili tüm bilgiler bir XML dokümanında tutulmaktadır. Farklı türden çalışan personel, kendi amacına uygun farklı detay seviyelerinde bilgiye ihtiyaç duyabilecektir. XSL tabanlı çözümde farklı ihtiyaçlar için gerekli her farklı görünüm için bir XSLT dokümanı tanımlanır. Örneğin satış elemanı siparişin durumuyla ilgilenirken, muhasebe personeli ödeme ilgili detaylarla ilgilenecektir.
XSLT, XSL’in en önemli bileşenidir ve bir XML dokümanının diğer bir XML ya da farklı bir düzendeki bir dokümana nasıl dönüşeceğini tanımlar. Burada giriş dokümanı XML olarak kodlanmış olduğundan, içeriği her zaman bir ağaç veri yapısı ile göstermek mümkündür. XSLT bu ağaçtaki her bir düğümün çıkışta nasıl bir veri yapısına dönüştürüleceğini tanımlamamıza olanak sağlayan çeşitli yapılar içerir. Bu dönüşümden amaç içeriği farklı bir amaçla sunmak olabilir ya da içerik içerisinden amaca uygun bilgiler çıkarmak olabilir. Örneğin, futbol liginde tüm sezonlar boyunca oynanan maçlara ilişkin istatistik bilgilerinin tutulduğu bir büyük XML dokümanından, bir takıma ilişkin dış saha performansını yıllara göre değişimini elde etmek için XSLT teknolojisinden yararlanabiliriz. Bu açıdan, XSLT’yi İlişkisel Veritabanı Yönetim Sistemlerinde sıklıkla kullanılan SQL’e (Structured Query Language) benzetebiliriz. Bunun yanında, XSLT’yi XSL-FO ile birlikte, içeriği sunum amaçlı olarak PDF (Portable Document Format) ya da Microsoft Word gibi farklı formatlara dönüştürmek amacı ile de kullanabiliriz.
Bu yazıda bu yapıları inceleyeceğiz. Daha sonra giriş ağacı üzerinde daha rahat dolaşmamızı sağlayan XPath teknolojisini tanıyacağız. XSLT dönüşümünü tanımlarken XPath’i kullanacağız. Böylelikle, karmaşık dönüşümleri, daha basit bir gösterimle ifade edebilme yeteneğine kavuşmuş olacağız. Tüm bu XSL teknolojileri W3C’nin birer standardıdır. 
XSL ile kodlanmış bir dokümanın kök elemanı <xsl:stylesheet> ya da <xsl:transform> olmalıdır. Buna göre aşağıdakiler geçerli bir tanımlamadır:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
ya da
<xsl:transform version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
Bir uygulama üzerinde XSLT’nin nasıl çalıştığını inceleyelim. Uygulamamıza giriş olarak vermek üzere ülkelere ilişkin bilgilerin yeraldığı bir XML dokümanı kullanacağız:
<?xml version="1.0" encoding="UTF-8"?> 
<countries>     
   <country>         
      <Code>AFG</Code> 
      <Name>Afghanistan</Name>
      <Continent>Asia</Continent>
      <Region>Southern and Central Asia</Region>              
      <SurfaceArea>652090.00</SurfaceArea>         
      <IndepYear>1919</IndepYear>            
      <Population>22720000</Population>            
      <LifeExpectancy>45.9</LifeExpectancy>         
      <GNP>5976.00</GNP>
      <GNPOld/>         
      <LocalName>Afganistan/Afqanestan</LocalName>            
      <GovernmentForm>Islamic Emirate</GovernmentForm>         
      <HeadOfState>Mohammad Omar</HeadOfState>           
      <Capital>1</Capital>
      <Code2>AF</Code2>     
    </country>
    .
    .
    .
</countries>
Şimdi nüfusu 50 milyonun üzerinde olan ülkelerin listesini HTML tablo olarak çıkışa aktarn bir XSL dönüşümü tanımlayalım:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="html"/>
    <xsl:template match="/">
        <html>
            <head>
                <title>Nüfus Yoğun Ülkeler</title>
            </head>
            <body>
                <table border="1">
                    <thead>
                        <tr>
                            <th>Ülke Adı</th>
                            <th>Bağımsızlık Yılı</th>
                            <th>Nüfusu</th>
                            <th>Yüz Ölçümü</th>
                            <th>Nüfus / Yüzölçümü</th>
                        </tr>                            
                    </thead>
                    <tbody>
                        <xsl:for-each select="countries/country[Population &gt; 50000000]">
                           <xsl:sort select="Population" order="ascending"/>
                            <tr>
                                <td>
                                    <xsl:value-of select="Name"/>
                                </td>
                                <td>
                                    <xsl:value-of select="IndepYear"/>
                                </td>
                                <td>
                                    <xsl:value-of select="Population"/>
                                </td>
                                <td>
                                    <xsl:value-of select="SurfaceArea"/>
                                </td>
                                <td>
            <xsl:value-of select="format-number(Population div SurfaceArea,'###,###.00')"/>
                                </td>                            
                            </tr>                   
                        </xsl:for-each>
                    </tbody>
                </table>                    
            </body>
        </html>
    </xsl:template>
</xsl:stylesheet>

Yukarıda verilen dönüşüm uygulandığında üretilen HTML aşağıda verilmiştir:


Ülke Adı Bağımsızlık Yılı NüfusuYüz Ölçümü Nüfus / Yüzölçümü
India 1947 1013662000 3287263.00 308.36
Nigeria 1960 111506000 923768.00 120.71
Japan -660 126714000 377829.00 335.37
China -1523 1277558000 9572900.00 133.46
Bangladesh 1971 129155000 143998.00 896.92
Russian Federation 1991 146934000 17075400.00 8.61
Pakistan 1947 156483000 796095.00 196.56
Brazil 1822 170115000 8547403.00 19.90
Indonesia 1945 212107000 1904569.00 111.37
United States 1776 278357000 9363520.00 29.73
Ukraine 1991 50456000 603700.00 83.58
Congo, The Democratic Republic of the 1960 51654000 2344858.00 22.03
Italy 1861 57680000 301316.00 191.43
France 843 59225700 551500.00 107.39
United Kingdom 1066 59623400 242900.00 245.46
Thailand 1350 61399000 513115.00 119.66
Ethiopia -1000 62565000 1104300.00 56.66
Turkey 1923 66591000 774815.00 85.94
Iran 1906 67702000 1648195.00 41.08
Egypt 1922 68470000 1001449.00 68.37
Philippines 1946 75967000 300000.00 253.22
Vietnam 1945 79832000 331689.00 240.68
Germany 1955 82164700 357022.00 230.14
Mexico 1810 98881000 1958201.00 50.50

for-each elemanı seçilen bir düğümün alt ağacında yatayda yer alan tüm select özniteliği ile verilen düğümlerin taranmasını sağlar.
sort elemanı for-each ile beraber kullanılır ve for-each ile taranan düğümlerin değerlerinin sıralanmasını sağlar.

if elemanı düğümün değerine göre dönüşümü farklılaştırmak için kullanılır. Genel yazımı aşağıda verilmiştir:
<xsl:if test="koşul"> 
 ... ... koşul doğru olduğunda yapılması gereken işlemler... ... 
</xsl:if>

choose elemanı if elemanına benzer bir amaçla kullanılır. Burada programlama dillerindeki if-else yapısına karşı düşer. Genel yazım biçimi aşağıda verilmiştir:
<xsl:choose> 
   <xsl:when test="koşul"> ... çıkış ... </xsl:when> 
   <xsl:otherwise> ... çıkış .... </xsl:otherwise> 
</xsl:choose>

Bir XSLT dokümanı içinde birden fazla şablon tanımlayabiliriz. Bu şablonların hangi sırayla uygulanacağını apply-templates elemanı ile kontrol edebiliriz. apply-templates elemanının select özniteliği şablonun hangi düğüme ya da alt ağaca uygulanacağını tanımlar. 
XPath işletim sistemlerindeki dosya isimlendirmelerine benzer şekilde XML ağacındaki düğümleri tanımlamak üzere geliştirilmiştir ve XSLT dönüşümlerinde kullanılır. Bunun yanında XPath iki karakter katarını karşılaştırma, sayısal işlemler, dizi işlemleri gibi çok sayıda fonksiyon içerir. Böylelikle XPath XSLT’ye önemli bir işlevsellik kazandırır. XPath XML ağacındaki düğümlerin seçilmesi amacıyla bazı gösterimlerden yararlanır. Bu gösterimler ve anlamları aşağıdaki tabloda verilmiştir.


Gösterim Anlamı
 Düğüm adı Verilen düğümün tüm çocuk düğümlerini belirtir
 / Kök düğümü belirtir
 // Dokümanda her nerede olursa olsun tüm düğümleri belirtir
 . O anki düğümü belirtir
 .. O anki düğümün ebeveyn düğümünü belirtir
 @ Özniteliği belirtir

Yüklemler belirli bir düğümü ya da belirli bir değeri içeren düğümü bulmak için kullanılır. Yüklemler her zaman köşeli parantez içinde verilirler. Aşağıdaki tabloda sıkça kullanılan yüklemler bir örnekle listelenmiştir.

Gösterim Sonuç
 /katalog/kitap[1] Katalogda yer alan ilk kitabı seçer
 /katalog/kitap[last()] Katalogdaki son kitabı seçer
 /katalog/kitap[last()-1] Katalogda ondan bir önceki kitabı seçer
 /katalog/kitap[position()<3] Katalogdaki ilk iki kitabı seçer
 //kitap[@kod] Kodu olan tüm kitapları seçer
 //kitap[@kod='42'] Kod değeri 42 olan kitapları seçer
 /katalog/kitap[fiyat<20] Fiyatı 20’den küçük olan kitapları seçer
 /katalog/kitap[fiyat<20]/başlık  Fiyatı 20’den küçük olan kitap başlıklarını seçer

Aşağıdaki tabloda ise XPath ifadelerinde kullanabileceğimiz operatörler tanımlanmıştır:
Simge
Anlamı
Toplama 
-
Çikarma
*
Çarpma
div
Bölme
=
Eşitlik testi
!=
Eşitsizlik testi
<
Küçüklük testi
<=
Küçük eşitlik testi
>
Büyüklük testi
>=
Büyük eşitlik testi
or
Mantıksal veya
and
Mantıksal ve
mod
Mod (Bölümden kalan)

XPath eksenleri o anki düğüme bağıl olarak düğüm kümelerinin tanımlanabilmesine olanak sağlar. Aşağıdaki tabloda XPath’de kullanabileceğiniz eksenler ve anlamları listelenmiştir:

Eksen
Anlamı
ancestor 
Bulunulan düğümün tüm düzeylerdeki ebeveynlerini seçer
ancestor-or-self
Bulunulan düğümü de içermek üzere tüm düzeylerdeki ebeveynlerini seçer
attribute
Bulunulan düğümün tüm özniteliklerini seçer
child
Bulunulan düğümün tüm çocuk düğümlerini seçer
descendant
Bulunulan düğümün tüm düzeylerdeki çocuklarını seçer
descendant-or-self
Bulunulan düğümü de içermek üzere tüm düzeylerdeki çocuklarını seçer
following
Bulunulan düğümün kapatan takısından sonra tüm elemanlari seçer
following-sibling
Bulunulan düğümü izleyen tüm kardes dügümleri seçer
parent
Bulunulan düğümün ebeveyn düğümünü seçer
preceding
Bulunulan düğümün açan takısından önceki dokümanda yer alan tüm elemanlari seçer
preceding-sibling
Bulunulan düğümün kendinden önceki tüm kardeslerini seçer
self
Bulunulan düğümün kendisini seçer



Şimdi başka bir örneği inceleyeceğiz. Bu örnekte XSD ile verilmiş bir XML dokümanı kullanacağız: 

otomobiller.xml
<?xml version="1.0" encoding="UTF-8" ?>
<otomobiller  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.omegaegitim.com/bte550/2011/hw2 otomobil.xsd"
             xmlns="http://www.omegaegitim.com/bte550/2011/hw2">
    <otomobil marka="Ford" model="Mustang">
        <uzunluk birim="mm">4610</uzunluk>
        <genislik birim="mm">1824</genislik>
        <yükseklik birim="mm">1351</yükseklik>
        <agirlik birim="kg">1490</agirlik>
        <bagaj_hacmi birim="m3">309</bagaj_hacmi>
        <motor_hacmi birim="cc">4601</motor_hacmi>
        <silindir_adedi birim="adet">8</silindir_adedi>
        <beygir_gucu birim="hp">228</beygir_gucu>
        <yuz_km_sn birim="sec">5.3</yuz_km_sn>
        <dingil_mesafesi birim="cm">1753</dingil_mesafesi>
        <yakit_tuketimi birim="lt">9.1</yakit_tuketimi>
    </otomobil>
    <otomobil marka="Ford" model="Mondeo">
        <uzunluk birim="mm">4214</uzunluk>
        <genislik birim="mm">1802</genislik>
        <yükseklik birim="mm">1573</yükseklik>
        <agirlik birim="kg">1250</agirlik>
        <bagaj_hacmi birim="m3">255</bagaj_hacmi>
        <motor_hacmi birim="cc">1600</motor_hacmi>
        <silindir_adedi birim="adet">4</silindir_adedi>
        <beygir_gucu birim="hp">110</beygir_gucu>
        <yuz_km_sn birim="sec">12.3</yuz_km_sn>
        <dingil_mesafesi birim="cm">1913</dingil_mesafesi>
        <yakit_tuketimi birim="lt">10.1</yakit_tuketimi>
    </otomobil>
    <otomobil marka="Ford" model="Focus">
        <uzunluk birim="mm">3897</uzunluk>
        <genislik birim="mm">1673</genislik>
        <yükseklik birim="mm">1350</yükseklik>
        <agirlik birim="kg">1203</agirlik>
        <bagaj_hacmi birim="m3">254</bagaj_hacmi>
        <motor_hacmi birim="cc">1600</motor_hacmi>
        <silindir_adedi birim="adet">4</silindir_adedi>
        <beygir_gucu birim="hp">120</beygir_gucu>
        <yuz_km_sn birim="sec">11.6</yuz_km_sn>
        <dingil_mesafesi birim="cm">1672</dingil_mesafesi>
        <yakit_tuketimi birim="lt">12.1</yakit_tuketimi>
    </otomobil>
    <otomobil marka='Renault' model='Fluence'>
        <uzunluk birim='mm'>3319</uzunluk>
        <genislik birim='mm'>1762</genislik>
        <yükseklik birim='mm'>1642</yükseklik>
        <agirlik birim='kg'>1500</agirlik>
        <bagaj_hacmi birim='m3'>312</bagaj_hacmi>
        <motor_hacmi birim='cc'>1600</motor_hacmi>
        <silindir_adedi birim="adet">4</silindir_adedi>
        <beygir_gucu birim='hp'>125</beygir_gucu>
        <yuz_km_sn birim='sec'>8.3</yuz_km_sn>
        <dingil_mesafesi birim='cm'>1632</dingil_mesafesi>
        <yakit_tuketimi birim='lt'>15.1</yakit_tuketimi>
    </otomobil>
    <otomobil marka='Renault' model='Megane'>
        <uzunluk birim='mm'>4209</uzunluk>
        <genislik birim='mm'>1782</genislik>
        <yükseklik birim='mm'>1641</yükseklik>
        <agirlik birim='kg'>1602</agirlik>
        <bagaj_hacmi birim='m3'>350</bagaj_hacmi>
        <motor_hacmi birim='cc'>1800</motor_hacmi>
        <silindir_adedi birim="adet">4</silindir_adedi>
        <beygir_gucu birim='hp'>145</beygir_gucu>
        <yuz_km_sn birim='sec'>15.3</yuz_km_sn>
        <dingil_mesafesi birim='cm'>1651</dingil_mesafesi>
        <yakit_tuketimi birim='lt'>10.1</yakit_tuketimi>
    </otomobil>
    <otomobil marka='Honda' model='Civic'>
        <uzunluk birim='mm'>3962</uzunluk>
        <genislik birim='mm'>1752</genislik>
        <yükseklik birim='mm'>1292</yükseklik>
        <agirlik birim='kg'>1648</agirlik>
        <bagaj_hacmi birim='m3'>401</bagaj_hacmi>
        <motor_hacmi birim='cc'>1600</motor_hacmi>
        <silindir_adedi birim="adet">4</silindir_adedi>
        <beygir_gucu birim='hp'>168</beygir_gucu>
        <yuz_km_sn birim='sec'>15.3</yuz_km_sn>
        <dingil_mesafesi birim='cm'>1852</dingil_mesafesi>
        <yakit_tuketimi birim='lt'>16.1</yakit_tuketimi>
    </otomobil>
    <otomobil marka='Honda' model='Jazz'>
        <uzunluk birim='mm'>3971</uzunluk>
        <genislik birim='mm'>1943</genislik>
        <yükseklik birim='mm'>1672</yükseklik>
        <agirlik birim='kg'>1532</agirlik>
        <bagaj_hacmi birim='m3'>376</bagaj_hacmi>
        <motor_hacmi birim='cc'>1400</motor_hacmi>
        <silindir_adedi birim="adet">4</silindir_adedi>
        <beygir_gucu birim='hp'>120</beygir_gucu>
        <yuz_km_sn birim='sec'>7.9</yuz_km_sn>
        <dingil_mesafesi birim='cm'>1962</dingil_mesafesi>
        <yakit_tuketimi birim='lt'>11.1</yakit_tuketimi>
    </otomobil>
    <otomobil marka='Honda' model='City'>
        <uzunluk birim='mm'>4986</uzunluk>
        <genislik birim='mm'>1954</genislik>
        <yükseklik birim='mm'>1574</yükseklik>
        <agirlik birim='kg'>1834</agirlik>
        <bagaj_hacmi birim='m3'>297</bagaj_hacmi>
        <motor_hacmi birim='cc'>1600</motor_hacmi>
        <silindir_adedi birim="adet">4</silindir_adedi>
        <beygir_gucu birim='hp'>135</beygir_gucu>
        <yuz_km_sn birim='sec'>15.3</yuz_km_sn>
        <dingil_mesafesi birim='cm'>1943</dingil_mesafesi>
        <yakit_tuketimi birim='lt'>14.7</yakit_tuketimi>
    </otomobil>
    <otomobil marka='Honda' model='Accord'>
        <uzunluk birim='mm'>3721</uzunluk>
        <genislik birim='mm'>1932</genislik>
        <yükseklik birim='mm'>1672</yükseklik>
        <agirlik birim='kg'>1203</agirlik>
        <bagaj_hacmi birim='m3'>402</bagaj_hacmi>
        <motor_hacmi birim='cc'>1250</motor_hacmi>
        <silindir_adedi birim="adet">4</silindir_adedi>
        <beygir_gucu birim='hp'>140</beygir_gucu>
        <yuz_km_sn birim='sec'>15.3</yuz_km_sn>
        <dingil_mesafesi birim='cm'>1629</dingil_mesafesi>
        <yakit_tuketimi birim='lt'>12.4</yakit_tuketimi>
    </otomobil>
</otomobiller>
otomobil.xsd:
<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="http://www.omegaegitim.com/bte550/2011/hw2"
           targetNamespace="http://www.omegaegitim.com/bte550/2011/hw2"
           elementFormDefault="qualified">
    <xs:element name="otomobiller">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="otomobil" minOccurs="1" maxOccurs="unbounded">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="uzunluk" type="olcuTipi"/>
                            <xs:element name="genislik" type="olcuTipi"/>
                            <xs:element name="yükseklik" type="olcuTipi"/>
                            <xs:element name="agirlik" type="olcuTipi"/>
                            <xs:element name="bagaj_hacmi" type="olcuTipi"/>
                            <xs:element name="motor_hacmi" type="olcuTipi"/>
                            <xs:element name="silindir_adedi" type="olcuTipi"/>
                            <xs:element name="beygir_gucu" type="olcuTipi"/>
                            <xs:element name="yuz_km_sn" type="olcuTipi"/>
                            <xs:element name="dingil_mesafesi" type="olcuTipi"/>
                            <xs:element name="yakit_tuketimi" type="olcuTipi"/>
                        </xs:sequence>
                        <xs:attribute name="marka" type="xs:string"
                                      use="required"/>
                        <xs:attribute name="model" type="xs:string"
                                      use="required"/>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:complexType name="olcuTipi">
        <xs:simpleContent>
            <xs:extension base='xs:decimal'>
                <xs:attribute name="birim" type="birimTipi" use="required"/>
            </xs:extension>
        </xs:simpleContent>
    </xs:complexType>
    <xs:simpleType name="birimTipi">
        <xs:restriction base="xs:string">
            <xs:enumeration value="mm"/>
            <xs:enumeration value="cm"/>
            <xs:enumeration value="km"/>
            <xs:enumeration value="m"/>
            <xs:enumeration value="sec"/>
            <xs:enumeration value="adet"/>
            <xs:enumeration value="hp"/>
            <xs:enumeration value="m3"/>
            <xs:enumeration value="lt"/>
            <xs:enumeration value="cc"/>
            <xs:enumeration value="kg"/>
        </xs:restriction>
    </xs:simpleType>
</xs:schema>

Şimdi yüksek motor hacimli araçları HTML tablo olarak listeyecek bir XSL yazalım:
araba1.xsl:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                xmlns:car="http://www.omegaegitim.com/bte550/2011/hw2"
                version="1.0">
    <xsl:output method="html"/>
    <xsl:template match="/car:otomobiller">
        <html>
            <head>
                <title>Yüksek motor hacimli araçlar</title>
            </head>
            <body>
                <table border="1">
                    <thead>
                        <tr>
                            <th>Marka</th>
                            <th>Model</th>
                            <th>Genişlik</th>
                            <th>Yükseklik</th>
                            <th>Ağırlık</th>
                            <th>Motor Hacmi</th>
                        </tr>                            
                    </thead>
                    <tbody>
   <xsl:for-each 
    select="car:otomobil[car:motor_hacmi &gt; 1500 and car:motor_hacmi &lt; 2000]">
   <xsl:sort select="car:agirlik" order="decending"/>
                                <tr>
                                    <td>
                                        <xsl:value-of select="@marka"/>
                                    </td>
                                    <td>
                                        <xsl:value-of select="@model"/>
                                    </td>
                                    <td>
                                        <xsl:value-of select="car:genislik"/>
                                    </td>
                                    <td>
                                        <xsl:value-of select="car:yükseklik"/>
                                    </td>
                                    <td>
                                        <xsl:value-of select="car:agirlik"/>
                                    </td>
                                    <td>
                                        <xsl:value-of select="car:motor_hacmi"/>
                                    </td>
                                </tr>                          
                        </xsl:for-each>
                    </tbody>
                </table>
            </body>
        </html>
    </xsl:template>
</xsl:stylesheet>

Örnekleri içeren kodları NetBeans projesi olarak bu bağlantıdan indirebilirsiniz.