Friday, November 1, 2002

XPath İle Çocuk Düğümleri Toplamak

Farzedelim ki, aşağıda örneği gösterilen dosya içinden eCRM baslığı taşıyan etiketlerin altındaki bütün çocuk düğümleri toplamak istiyoruz.

<?xml version="1.0" encoding="iso-8859-9"?>
<kategoriler>
<kategori baslik="eCRM">
<yazi>a_etl.xml<tarih>19 Nisan 2002</tarih></yazi>
<yazi>a_hangi_verileri_alalim.xml<tarih>19 Nisan 2002</tarih></yazi>
<yazi>a_internet_veri_ambari.xml<tarih>19 Nisan 2002</tarih></yazi>
<yazi>a_musteri_kayitlari.xml<tarih>19 Nisan 2002</tarih></yazi>
<yazi>a_oracle_kavramlari.xml<tarih>19 Nisan 2002</tarih></yazi>
<yazi>a_oracle_kullanim.xml<tarih>19 Nisan 2002</tarih></yazi>
<yazi>a_oracle_parallel.xml<tarih>19 Nisan 2002</tarih></yazi>
<yazi>a_oracle_query_optimize.xml<tarih>19 Nisan 2002</tarih></yazi>
<yazi>a_veri_madenciligi.xml<tarih>19 Nisan 2002</tarih></yazi>
</kategori>
<kategori baslik="Genel">
<yazi>a_acik_anahtar_sifreleme.xml<tarih>19 Nisan 2002</tarih></yazi>
<yazi>a_continous_integration.xml<tarih>19 Nisan 2002</tarih></yazi>
<yazi>a_cvs.xml<tarih>19 Nisan 2002</tarih></yazi>
</kategori>
</kategoriler>



Bunun için şöyle bir XPath komutu vermemiz gerekecek.

/kategoriler/kategori[@baslik='"eCRM"']/yazi


Bu komut kategoriler, kategori altına gidip, eCRM baslığı taşıyan bütün yazı etiketlerinin değerlerini getirecektir. Java ile şöyle kodlama yapabiliriz.

  public ArrayList kategoriAltindakiYazilar(String kategori)
{
Document doc = belgeOku();
String xpath = "/kategoriler/kategori[@baslik='" + kategori + "']/yazi";
NodeList liste = null;
ArrayList sonListe = new ArrayList();

try {

liste = org.apache.xpath.XPathAPI.selectNodeList(doc, xpath);

} catch (javax.xml.transform.TransformerException e) { }


for (int i=0; i < liste.getLength(); i++) {
Element elem = (Element)liste.item(i);
sonListe.add(elem.getFirstChild().getNodeValue());
}

return sonListe;

}



getFirstChild (ilk çocuğu getir) çağrısına dikkatinizi çekmek istiyorum. Bu çağrı ile, zaten başka çocuğu olmayan yazı etiketinin alt değerini almış oluyoruz. Tabii getNodeValue (dügüm değerini getir) dememiz de gerekti. Anlamamız gereken nokta, 'yazı' altında bulunan değerin etiketin kendisinde değil, alt düğüm olarak başka bir düğümde durmasıdır.

Hemen JUnit testimizi yazalım:

  public void testYaziListe() throws Exception {
ArticleList liste = new ArticleList();
ArrayList l = liste.kategoriAltindakiYazilar("eCRM");
assertTrue(l.size() > 0);
}

İnternet Yayıncılığı ve XML

XML en çok İnternet yayıncılığı için uygun olmuştur. Bir önceki yazıda XML içeriğinin hiyerarşik, yani "ağaç-dalları" yapısında olduğunu söylemiştik. Genelde yazılar, yani dökümanlar boyle yapıya çok uygundurlar. Her yazının başlığı, başlık altında paragrafları, paragraf altında kelimeler, resimler ve İnternet linkleri olabilir.

Ayrıca XML istenilen "başlama/bitiş" işaretlerini kullanmanıza izin verir. Böyle olunca herkes kendine uyan XML yapısını önceden planlayıp, onu kullanarak yazılarını yazabilir.

Daha önemlisi, XML kayıdını kullanarak, görsel "çevirmen program" XSLT kullanıp, XML içinden HTML, PDF gibi görsel sayfalar yaratabilirsiniz. Yani "içerik" ile görsel HTML dosyaları birbirinden ayrı tutmak mümkün olur. Bunun sayısız faydaları var.


* İçerik değişiklikleri daha rahat yapılabilir. Eğer yeni bir cümle eklemek istiyorsanız, nasıl gözükeceği ile kafa yormanıza gerek kalmaz.
* Yazılarınızın görsel olarak değiştirmek isterseniz, görsel çevirmen programı değiştirmeniz yeterlidir.

Mesela bu yazıyı ele alalım. Bu yazının basligi önce XML, sonra XSL (çevirmen) en son HTML olarak geçirdiği değişimleri görebilirsiniz.

XML
 XML ne işe yarar

XSL
  <xsl:template match="title">
<tr><td class="head">
<xsl:apply-templates/>
<br></br><img kaynak="images/spacerc1.gif" height="2" width="400"
border="0"></img></td></tr> <tr><td height="15"></td></tr>
</xsl:template>

HTML
<td class="head">XML ne ise yarar<br>
<img border="0" width="400" height="2" kaynak="images/spacerc1.gif"></td>
</tr><tr>
<td height="15"></td>

Gördüğünüz gibi XML dosyasında görsel hiçbir şey yok. XSL dosyası sadece "baslik" komutu nasıl HTML çevirisi yapılmalı, onu tarif ediyor. Bu ikisini (XML, XSL) beraber işlemden geçirdikten sonra (xalan adlı bir program kullanarak) sonuç HTML olarak gözüküyor.

Eğer bu yazının başlığını değistirmek istesem, XML dosyasından istediğim değisikliği yapıp, tekrar çevirmen programı işletirim. XSL dosyasına hiç dokunmama gerek yok. Zaten içerik, XML içinde ne olduğu daha belli: yani daha rahat okunabiliyor.

Eğer yazının gözükme şeklini değiştirmek istersem, XSL dosyasından yapabilirim bu değişikliği, "içerik" dosyasına dokunmama gerek yok. Bu iki şeyi birbirinden ayırmak, bize büyük rahatlık sağlayacaktır. Büyük siteleri kontrol eden programcılar/idareciler muhakkak bunun değerini anlayacaktır.

Ek:
* Projesinde bizzat çalıştığım Martha Stewart Omnimedia sitesi için, XML bazlı içerik idaresi kurduk. XML Spy ile yazı yazan içerik üreticileri, J2EE uyumlu bir ürün olan ATG Dynamo ile XSL uyguluyarak, HTML sonucunu görüyor, ve makaleyi gene XML olarak sonuç sitesine gönderebiliyorlar.
* Ünlü tasarımcı ve programcı Martin Fowler en son kitabının tamamını XML ile yazmıştır.

Kontrol Edilmeyen (Unchecked) Exception'lar

Java'nın sözdizim bağlamında çoğu programcıyı gereksiz yere uğraştıran ve vakit kaybına neden olan özelliklerinden biri, exception atan bir kod parçasını kullandığınızda kullanan tarafın ya try/catch koymaya, ya da bulunduğu metotun tanımına "throws xxException" gibi bir ifade eklemeye mecbur kalmasıdır. Tabii hepimizin bildiği gibi "throws xxException" ekleme yoluna giderseniz, bu eklemenin etkisi zincirleme olarak o metotu çağıran metota, ve oradan başka yerlere sıçrar, ve bir süre sonra bir bakmışız ki metotlarımızın yarısı aynı asalak ifadeyi içeriyor: method_x() throws Exception!

"En iyi kod, yazmadığım koddur" desturundan yola çıkarak, bu yazının geri kalanında kontrollü Exception kullanımını tavsiye etmeyeceğiz. Kurumsal Java programcılığı esnasında zaten fazla olan teknoloji çorbası ile uğraşırken "sadece istenilen şeyi söylemek, geri ile gerekince ilgilenmek" en iyisidir. Daha kısa zamanda, daha basit/bakımlı kod yazmak bunu gerektirir.

Şimdi, final tavsiyeyi vermeden önce Java exception mimarisine bir bakalım.

Java ve Exception'lar

Java sözdizim yapısında iki tür exception vardır. Kontrollü (checked) exception, ve kontrolsüz (unchecked) exception.

Çoğumuzun bildiği gibi kontrollü exception durumunda, eğer bir kod parçası içinde 'throw new xxxException' gibi bir ibare mevcutsa, kullanan kod try/catch "yakalayıcıları" bulundurmaya mecburdur. Bu gereklilik bizzat Java derleyicisi üstümüzde zorlanan (enforce) bir gerekliliktir, kaçış yoktur.

Kontrolsüz exception kullanımında ise herhangi bir servis kod parçası kontrolsüz exception fırlatabilir, fakat çağırım yapan taraf bu exception'ı yakalamaya (ya da bulunduğu metot tanımına "throws xxException" eklemekte) mecburiyeti yoktur. RuntimeException bunun güzel bir örneğidir.

Java tasarımcıları baştan beri kontrolsüz yanında kontrollü exception kullanımını da bir seçenek olarak sunmayı seçmişlerdi. Ayrıca, zamanın ortak aklı da (conventional wisdom) bir şekilde kontrollü exception kullanımını ön plana çıkarmıştır (çünkü ilk Java kod örneklerinde böyleydi). Fakat aslında, Java tasarımcılarının bu seçiminin arkasında müthiş zeka aramamak gerekir. İstekleri sadece şuydu:

Programcının, çağırdiğı kodun ne yaptığından "haberdar olması", ve o kodu kullanırken "bunun sonuçlarına katlanıyorum :)" ibaresini yazılı olarak kodunun içine koyması.

Fakat bu saf istek, kurumsal Java bağlamında artık bir zul olmaya başlamıştır. Kurumsal Java kodları bir API "denizi" içinde yüzer, ve 3-4 dış kütüphane kullanan bir kodda artık çok fazla sayıda try/catch ibaresi görmek mümkündür, ya da metot tanımı bağlamında gereksiz bir ekleme enflasyonu ortaya çıkmaktadır.

Bu sebeple yazımızın tavsiyesi kurumsal uygulamalarda (web/telekom/vs) kontrolsüz Exception kullanılmasıdır. Bu Exception yöntemi ile, bir Exception'ı, "sadece istediğinizde" try/catch ile yakalamanız yetiyor, eğer hiçbir Exception ile ilgilenmiyorsanız, derleyici size bir hatırlatmada/zorlamada bulunmuyor. Bu sayede kodunuz daha temiz kalıyor.

Tabii eklemek gerekir ki, içinde Exception atılması muhtemel bir çağrıyı yapan kodun, o kontrolsüz Exception'ı yakalamaması demek, bu Exception'ın daha üst seviyelerde yakalanmayacağı demek değildir. Exception kurallarına göre yakalanmayan bir Exception zaten çağrı sıralamasında üste doğru çıkacaktır, ve kontrolsüz şartında sadece ilgilenen bir yakalayıcı tarafından yakalanabilir. Zaten, her uygulama bir "en üst seviye" yakalayıcı genelde olduğu için bu, o Exception'ın eninde sonunda bir yerde yakalanacağı anlamına gelir. Ama bu yakalayıcı bir tane, ve her yerde olmayan bir ekleme olduğu için kod temizliği için bir tehlike arz etmez.

Bu tavsiye ışığında Exception muamele sistemimiz daha temiz ve bakımı rahat hâle gelekcektir. İlginçtir ki, kontrollü Exception seçeneği, diğer "pür" nesnesel dillerde mevcut değildir: Ada, Eiffel, Ruby, Phyton dillerinin hepsi kontrolsüz Exception atarlar. Bu dillerden Ada, gerçek zamanlı (real-time) ve kritik misyon (mission critical) sistemlerde kullanıldığına göre (askeri, uzay sistemlerinde), kontrolllü Exception'ların pek o kadar da hayati olmadığı ortaya çıkmaktadır.