Mesajlar etiketlendi xml dump

MySQL XML Dump-II

mysql den xml’e dump ettik ya sonra :

Artık elimizde bir XML dokumanımız var, şöyle düşünün bu XML dokumanı belki de başka bir sistemde SQL Server tarafından belkide Oracle tarafından oluşturulmuş bir dokuman da olabilir. Çünkü artık evrensel veri depolama kurallarına(biraz abartılı geliyor gibi :-) ) uygun olarak oluşturulmuş bir dokumanınız var, sizde bu kuralları bilir ve kurallara uygun olarak okursanız hangi veritabanı tarafından oluşturulduğu ne farkeder, bütün veritabanı dökümlerini mysql’e atabilirsiniz.

Yazının bu bölümünde yine başka bir sınıf yapısı üzerinde duracağız, bu sefer sınıfın adı xml2mysql. Yazının tamamında, daha önceki yazılarımdan birisinde de ele aldığımız PHP’nin 2 tane XML parse etme aracından birisi olan Expat’ı kullanacağız. Yoğun olarak Expat kullanacağımız için eğer okumadıysanız önce Expat temelleri ile ilgili olan o yazıyı okumanızı tavsiye ederim.

mySQL verisini xml dokumanı haline getirirken XML dokumanının yapısını hatırlarsınız.

icerik



En fazla 3 kademe giden dokumanlar oluşturuyoruz. En üst kademede veritabanı ismi hemen altında tablo isim etiketleriyle oluşturulmuş kayıtlar, kayıt kümelerinin içinde ise alan isimleri ve içerikleri bulunuyor.
Her veritabanı tablolardan, tablolar alanlardan, alanlarda ise içerikler bulunduğundan (alanın boş bırakılması farketmez) bütün veritabanı XML dokumanları genel olarak en fazla ve en az 3 kademeden oluşur diyebiliriz.

Scripti Expat ile yazacağız, expat bildiğiniz gibi olay tabanlı bir parser idi. Yani başlangıç etiketine, bitiş etiketine ve karakter verisine rastaladığında bizim belirlediğimiz fonksiyonları çağırıyor ve rastladığı elementle ilgili bilgileri bu fonksiyona aktarıyordu.
Programımızda expat bize sadece etiketlere ve verilere rastladığında etiket ismini ve veriyi vereceğinden, yapısını bilmediğimiz bir veritabanında hangi etiketin tablo ismi,hangi etiketin alan ismi olduğunu bulmak bize kalıyor. Ama düşününce zor görünmesine rağmen zor olmayan bir işlem, çünkü elimizde ayırtedici bir özellik var.

1. Veritabanı ismi agaç yapısında en üst kademede
2. TAblo isimleri yani kayıtların başlangıç etiketleri 2. kademede
3. Alan isimleri ise 3.kademede karşımıza çıkıyor.
4. Sadece alan isimli etiketler karakter verisi taşıdığından script içinde expat’ın bize verdiği bütün karakter verileri doğrudan en son rastlanılmış başlangıç etiketine sahip alanın (Tablo alanı yani) içeriği sayılabilir.

Yani toparlarsak program içinde yapmamız gereken işlem :

1. 1- Kademe (derinlik) bilgisini bir değişkende tutmak
2. 2- Başlangıç etiketlerine rastlandığında derinliği bir artırmak (Kademe yerine daha uygun bir kelime olan derinliği kullanacağız artık)
3. 3- Bitiş etiketine rastlandığında derinliği bir azaltmak.

Öyleyse bir başlangıç etiketine rastlandığında

1. Eğer derinlik 1 ise bu root elementidir. Ve örneğimize göre veritabanı ismini içerir.
2. Eğer derinlik 2 ise bu bir tablo ismidir ve bir kayıt bilgileri başlangıcı olarak kabul edilmelidir.
3. Eğer derinlik 3 ise bu bir alan (field) ismidir.
4. Eğer derinlik 3 ten büyük ise XML dokumanı geçerli bir veritabanı yapısı içermemektedir.

Peki etiketleri ayrıştırdık ve kayıtları,tabloları,alanları bulduk. Bir kayıt bilgisini nasıl bir SQL sorgusu haline getireceğiz ?

Yapacağımız işlem şu :
Dikkat ettiyseniz XML yapısına

1
mkarabulut

2
Raist

ben.jpg
jpg

Her kayıt bilgisi bir tablo ismi taşıyan etiket – kayıdın bulunduğu tablo – ile başlıyor, sonra bu etiket kapanana kadar rastlanılan bütün etiketler bu kayıt ile ilgili bilgileri tutuyor. Yakaladınız di mi?

1. 1- Yapmamız gereken açılmış ve kapanmamış etiketlerin isimlerini tutmak
2. 2- Derinlik bilgisine göre açık etiketlerde rastlanılan bilgileri değerlendirmek.
3. 3- Bir etiket kapatıldığında ismini açık etiketler listesinden çıkarmak.

Açık etiketlerin isimlerini tutmamızın sebebi şöyle bi şey : Mesela bir karakter verisine rastladık,expat olay tabanlı olduğu için bu karakter verisinin hangi etikete ait olduğunu bize söylemeyecektir. Bunun için biz en son açılan ve kapatılmayan etiketin bu karakter verisine sahip olduğunu bileceğiz.

Bu kadar açıklamaya rağmen aslına bakılırsa en iyi yol sizin kodu bir parça incelemeniz olacaktır, çok karışık olmadığı için dikkatli incelediğinizde ve açıklamaları göz önünde bulundurduğunuzda olaylar daha net olacaktır.

Sınıf yapısı ile ilgili olarak: Hatırlarsınız, mysql2xml sınıfında eksikliklerden biriside hata kontrolleri idi. Bu sefer hata kontrollerini sınıfa dahil ettim. Ayrıca yine istatistik nevinden bilgileri toparlayan bir metodumuz var.

Buyrun xml2mysql sınıfımız …
parser=xml_parser_create($encoding);
xml_set_object($this->parser,&$this);
xml_set_element_handler($this->parser,”startE”,”endE”);
xml_set_character_data_handler($this->parser,”cData”);

$this->xmlfile=$xmlfile;
$this->setoption(XML_OPTION_CASE_FOLDING,false);
$this->setoption(XML_OPTION_TARGET_ENCODING,$encoding);

$this->depth=0;
$this->recordnum=0;
}

function setoption($option,$value){
xml_parser_set_option($this->parser,$option,$value);
}

function parse(){
if($file=@fopen($this->xmlfile,”r”)){
while ($xmlstr=fread($file,4096)){
if (!xml_parse($this->parser,$xmlstr,feof($file))){
$err = xml_error_string(xml_get_error_code($this->parser));
$err.= “
Satır :”.xml_get_current_line_number($this->parser);
$this->error[]=$err;
} // if !xml_parse
} // while
} else {
$this->error[]=”XML dosyası $file açılamadı”;
}
@fclose($file);

return ($this->error_exists() ? false : true);
} //function parser

function startE($parser,$name,$attr=”){
$this->opentags[]=$name;
if ($this->depth==0)
$this->root=$name;
if ($this->depth==1 && !in_array($name,$this->tables))
$this->tables[]=$name;

$this->depth++;

if ($this->depth>3){
$this->error[]=”XML dokumanı geçerli bir tablo yapısı içermiyor.”;
}
}

function cData($parser,$data){
$last=count($this->opentags)-1;
if (@$this->data[$$this->opentags[$last]]!=”")
$this->data[$this->opentags[$last]].=$data;
else
$this->data[$this->opentags[$last]]=$data;
}

function endE($parser,$name){
array_pop($this->opentags);
$this->depth–;
if ($this->depth==1){
//kayıt bilgileri bitti
$this->recordnum++;
$query=”INSERT INTO $name VALUES(“;
foreach ($this->data as $tag=>$veri){
if (!in_array($tag,$this->tables) && $tag!=$this->root)
$query.=”‘”.addslashes($veri).”‘,”;
}
$query=substr($query,0,-1);
$query.=”)”;
$this->queries[]=$query;
unset($this->data);
}
}

function querydb($localhost,$dbname,$user,$password){
if (!$this->error_exists()){
$conn=@mysql_connect($localhost,$user,$password);
if (@mysql_select_db($conn,$dbname)){
foreach ($this->queries as $query)
mysql_unbuffered_query($query);
} else {
$this->error[]=”Veritabanına bağlanılamadı.”;
return false;
}
} else {
return false;
}
}

function get_info($inf=”){
$info=array(
“Kayıt sayısı”=>$this->recordnum,
“Tablo sayısı”=>count($this->tables)
);
if ($inf!=”")
return $info[$inf];
else
return $info;
}

function error_exists(){
return count($this->error)>0 ? true : false;
}

function get_error(){
return @$this->error[count($this->error)-1];
}
} // class

?>
Kodu biraz inceleyin, yine tekrar edeceğim ama dikkatinizi toplamak için biraz dinlenin, çünkü bende çok yoruldum :)
Diğer sayfada açıklamalar ile devam edelim…
Class xml2mysql
Özellikler
* parser
* xml_file
* opentags
* data
* depth
* root
* tables
* recordnum
* queries
Metodlar
xml2mysql()
setoption()
parse()
startE()
endE()
cData()
querydb()
get_info()
error_exists()
get_error()

Özellik isimlerinden ve metod isimlerinden aslında ne işe yaradıkları anlaşılmaktadır. Zaten fonksiyon isimleri ve değişken isimleri seçilirken anlaşılır şeyler seçmek güzel bi yoldur. Peki diyeceksiniz neden ingilizce :) ? Buda kişisel bi seçim,sebebi basit, türkçe karakterlerin programlama dillerinde desteklenmemesi. (Belki de psikolojik bir sebebi de vardır,kimbilir ? :) )

Metodlardan kısaca söz edersek :

xml2mysql() : Constructor olan bu fonksiyonumuz tıpkı, bir önceki sınıf yapımızda olduğu gibi sınıf yapısı için gerekli bazı değişkenlere ilk değer atıyor. Bu ilk değerleri ise parametre olarak alıyor.
Yalnız burada bahsetmek istediğim bir fonksiyon var, expat makalesini okumuş olsanız bile size yeni olacak bir fonksiyon kullandık :

parser,&$this);
?>
//Bu fonksiyon sadece Expat ile OOP ‘i birlestirmek
//istediginiz zaman kullanilir. Normalde

//ile call-back fonksiyonlarını tanıttığınızda bu fonksiyonlar
//yazılan script içinde global olarak erişilebilen fonksiyonlar
//arasında aranır bulunamazsa hata verir.

Bir sınıf yapısı içindeki fonksiyonlar ise global olarak erişilebilen fonksiyonlar değildir ancak sınıf adı ve ‘->’ operatörü ile erişilir (obj->fonk() gibi). İşte tam burada eğer sınıf içindeki fonksiyonları call-back fonksiyonu olarak tanımlamak istiyorsak xml_set_object() fonksiyonunu kullanmamız gerekiyor. Fonksiyonun 2. parametresi ile sınıf nesnesine bir referans parametre olarak veriliyor ve böylece tanımlanan call-back fonksiyonları artık sınıf metodları oluyor. (Bu arada &$this kullanımı içindeki ‘&’ işaretini ve referansları bilmiyorsanız şimdilik sadece bu kullanımı öğrenin.)

setoption(): Tanımlanan XML parser’ın özelliklerini ayarlamak için kullanacağımız metoddur. Kısaca parametre olarak aldığı özelliği yine parametre olarak aldığı değer olarak ayarlar. Burada yine expat’ın bir fonksiyonunu kullanıyoruz.

xml_parser_set_option($parser,özellik integer değeri ,”Değer”);

Bu fonksiyon parser için iki tane şeyi ayarlar :

1- Büyük küçük harf hassasiyeti : XML dokumanı içinde rastlanılan etiketlerde büyük-küçük harf duyarlılığı ayarlanır. true verilirse bütün etiket isimleri parse işlemi sırasında büyük harfe dönüştürülür. false verilirse etiket isimlerinin orjinalliği korunur.

2- Karakter encoding : Parse edilen dokumanlar verilen karakter setine göre parse edilir. Eğer karakter setinin desteklemediği karakterler olursa, parse işlemi hata verir ve durur.

parse() : sınıf yapısına uygun olarak nesne oluşturulurken verilen XML dokumanı,karakter setine göre XML dokumanına parse işlemi yapılır. Bu işlem sırasında bir hata oluşursa nesnenin $error özelliğine hata tanımlaması aktarılır. Böylece bu işlem sırasında bir hata oluşmuşsa sınıfın diğer metodlarının çalışması parse işleminin başarısına bağlı olduğu için olması gerektiği gibi kontrol edilmiş olur.

startE(),endE(),cData() : Bu fonksiyonlar parser oluşturulurken tanımlamış olduğumuz call-back fonksiyonlarıdır. Bu fonksiyonların kısaca ne iş yaptıklarını bir önceki sayfada anlattığımızdan çok fazla ne yaptıklarından bahsetmeyeceğim. Yalnız kodu incelerken size yabancı gelebilecek fonksiyonlardan bahsetmek istiyorum.
addslashes() : Bu fonksiyon string içindeki zararlı olabilecek karakterlerin başına ‘\’ koyarak onları zararsız hale getirir.Bir örnekle çıklayayım :

Yukarıdaki sorgu çalıştığı anda hata verecektir,çünkü string içindeki ‘ karakteri sorguya eklendiğinde sorgu şöyle bir şey olacaktır.
UPDATE tablo SET text_alan=’Zararlı string ‘ asdasd’
Gördüğünüz gibi ‘ karakteri sorguda sorun çıkarmaktadır. İşte eğer bunun gibi sorgu için veritabanına gönderilecek stringler öncelikle addslashes() fonksiyonundan geçirilerek eğer varsa sorun çıkarabilecek karakterler olan ‘,” gibi karakterlerin önüne \ getirilerek zararsız hale getirilir.

in_array($değişken,$dizi) : Bu fonksiyon 1. parametresi ile verilen değer eğer 2. parametredeki dizi içinde varsa true yoksa false dönderir.

array_pop($dizi) : Bu fonksiyon parametre ile verilen dizi değişkenin son elemanını diziden çıkarır, böylece dizinin bir elemanı eksilmiş olur. Çıkarılan eleman fonksiyonda geri dönderilir.

unset($değişken) : Verilen değişkeni siler.

Fonksiyonlardan sonra birde değişik bir kullanım dikkatinizi çekmiş olmalı,mesela şu ifade :
return ($this->error_exists() ? false : true);

return bildiğiniz return ama,? : gibi şeylerde nedir diyorsanız, bunun if-else için bir kısayol olduğunu söylemem gerek. C++ ile uğraşanların hemen tanıdığı bu syntax if-else yerine kullanılmaktadır. Kullanımı

$değisken = $d > 5 ? “D 5 ten büyük” : “D 5 ten büyük değil ” ;

Eğer $d 5′ten büyükse ? işaretinden sonraki ifade $degisken değişkenine atanır, değilse : işaretinden sonraki değer atanır.
Daha değişik bir kullanım

5 && $d

Yukarıdaki örnekte karşılaştırma ifadelerinin sonucu true ise “Herşey tamam” değilse “Bi şeyler hatalı galiba” ekrana yazılacaktır.

querydb() : Sınıfın endE() metodu ile elde edilen kayıtlar SQL sorgularına dönüştürülmüştü, işte bu sorgular işlenmeyip hepsi sırasıyla $queries özelliğine atandı. Böylece $queries bir dizi değişken olmuştu. querydb() metodu ise işte bu sorguları teker teker mysql’e sorgu olarak gönderip,işlemiş oluyor. Parametre olarak veritabanına bağlanmak için gerekli server,veritabanı adı, kullanıcı adı, parola alıyor. Tabii ki hata kontrolleri var.

get_info() : Parse işlemi sırasında bulunan kayıt sayısı,tablo sayısı gibi değerler sınfın bazı değişkenlerine atılmıştı. get_info() fonksiyonu istenirse parametre olarak verilen özelliği,verilmezse dizi olarak bütün (Şu an için toplam 2 tane) özellikleri geri dönderir.

error_exists() : Eğer işlemler sırasında bir hata oluşmuşssa true, hata yoksa false dönderir.
get_error() : Eğer hata varsa oluşmuş olan en son hata tanımını geri dönderir.

Böylece sınıf yapımızı incelemiş olduk, eğer dikkatli incelerseniz sınıf yapısına yeni özellikler ve metodlar eklenebileceğini, hatta varolan özelliklerin bile bazılarının kullanılmadığını göreceksiniz.Mesela $this->tables rastlanılan tüm tabloların isimlerini tutmasına rağmen pek kullanılmamıştır. Parse işleminden sonra güzel bir get_info() metodu yazılabilir örneğin veya buna benzer bir şeyler…

Şimdi sınıf yapımızın nasıl kullanıldığını gösteren örnek bir kod inceleyelim :

Sınıf yapımız

parse()){
echo “Dokuman basariyla parse edildi,bilgiler : “;
foreach ($par->get_info() as $info=>$val){
echo “$info : $val
“;
}
echo “Sorgular isleniyor”
:
$par->querydb(“localhost”,”veritabani”,”mkarabulut”,”parola”);
if ($par->error_exists()) {
echo “Sorgular islenirken bir hata olustu :”;
echo $par->get_error();
} else {
echo count($par->queries). “sorgu basariyla islendi(mi?)”;
}

} else {
echo “Bir hata olustu:
“;
echo $par->get_error();
}
?>

Böylece xml’den mysql’e ve mysql’den xml’e veri dump etme işlemlerini bitirmiş olduk. Elimizde iki tane sınıf yapımız var,bunlar sadece bu yazıyı yazarken göstermek amacıyla yazılmış scriptlerdir. Tabii ki daha çok geliştirilebilir ve belki de hataları çıkabilir.
Ama siz buradaki mantığı ve gidişatı anladıysanız bu kodları geliştirmek sizin elinizde. Mesela benim ilk aklıma gelen yazının içinde de bahsettiğim gibi mysql2xml sınıfına XSLT desteği eklemekti. Veya mysql2xml sınıfına hata kontrol metodları eklemek gibi.
xml2mysql sınıfı ilk bakışta ilk sınıfa göre daha detaylı ve hatasız görünüyor, fakat doğrusunu söylemek gerekirse xml2mysql sınıfını BLOB yapıları içeren veritabanlarıyla hiç denemedim :) BLOB yani binary data belkide text olarak hata verecektir. Belkide bu sınıf için geliştirilmesi gereken nokta bu olabilir. Belki de olmayabilir ama bunları denemeyi ve çözmeyi size bırakıyorum :-)
xml2mysql sınıfının bir eksik görünen noktası ise veritabanı işlemleri sırasındaki hataları kontrol etmemesi,bu da geliştirilmesi gereken başka bir nokta olarak görülüyor.

Herneyse, umarım size yardımcı olmuş ve bir fikir sahibi olabilmişsinizdir.

Ve umarım bu yazılar aşağıdakiler için size yardımcı olmuştur.

1. Nesneye yönelik programlama
2. Expat kullanma
3. Yeni bir kaç PHP özelliği ve fonksiyonu öğrenme.
4. XML dokumanlarına biraz daha yakınlık

Şimdilik bu kadar, ayrılmadan önce bu yazı ile ilgili görüş, yorum ve eleştirilerinizi bana yazabileceğiniz hatırlatmak isterim, mail adresim mkarabulut@ceviz.net. Ayrıca forumumuzda her zaman sizin için bir thread vardır, tek yapmanız gereken forum.ceviz.net adresinden Net programlama kategorisine girmek, orada bu konu veya diğer PHP ağırlıklı konuları konuşabiliriz.

Görüşmek dileğiyle.

‘Stand firm in the straight path as you are commanded’

Yorum bırakın »

MySQL XML Dump-I

Merhaba,
Geçen yazımızda PHP-XML hakkında konuşmuştuk ve PHP’nin XML dokumanlarını kullanmak için bulunan araçlarından olan Expat fonksiyonlarını incelemiştik. Geçen sürede phpMyadmin’in son sürümlerinden birisini incelerken hepimizin bildiği veritabanı bilgisini dump etme özelliklerine bir de veriyi XML olarak dump etme özelliğini eklemiş olduklarını gördüm. Ama ne yazıkki XML verisini mysql’e dump etme özelliğini bulamadım,galiba yoktu…

İşte bugünkü yazımızın konusuda bu oldu böylece, yazı 2 bölümden oluşacak

1. 1- PHP ile mysql verisini XML’ye dump etme işlemi
2. 2- XML verisini mysql’e dump etme işlemi.

Başlayalım …

MYSQL’İ DUMP EDELİM
Öncelikle bugünkü yazımın kod ağırlıklı olacağını söyleyeyim, kendi yazacağımız 2 adet class dosyası ile yukarıda bahsettiğimiz iki işlemi yapacağız. Peki ama neden class yani OOP kullanacağız ?
1- Yazacağımız kod başka programcılar tarafından da kullanılabilir olacak
2- Script oldukça basit bi şekilde çalışacak bu yüzden başkaları tarafından da kolay bi şekilde geliştirilebilinir olmasını isteyeceğiz. Class içinde eksik olan – ver her API benzeri şeyde olması gereken – error kontrolü, işlemler sırasında oluşan durumlar hakkında bilgi veren fonksiyonlar çok karmaşık olmaması için class yapılarına eklenmedi.

XML dokumanının yapısı :
Bir mysql veritabanı bilgisini tutacak olan XML dokumanının yapısı sizce nasıl bir şey olmalıdır ? XML dokumanı bir ağaç yapısı içerdiğine göre veriler de onun içinde hiyerarşik olarak tutulacaktır. Yani hiyerarşi şöyle bi şey olacaktır

-

——
——–Veri
——
——
——–Veri
——
—-

——
——–Veri
——
——
——–Veri
——
—-

Aynen bu şekilde her etiketi içinde bir kayıt olacak şekilde kayıtlar altalta aynı hiyerarşik düzeyde sıralanacaktır. Farklı tablo kayıtları ise mesela gibi o tablonun ismini alan bir etiket ile aynen tablo1 de olduğu gibi kayıtlar sıralanacaktır. Örnek bir mysql bilgisi içeren XML dokumanı şöyle bi şeyler olmalıdır :
Mysql veritabanı şöyle olsun

Üyeler tablosu
_____________________
|uye_id| isim | soyisim |
—————————–
| 1 | mustafa | Karabulut |
—————————–
| 2 | Hakan | Müştak |
—————————–

Makaleler tablosu

|m_id | baslik | yazar |
———————————-
| 1 | php ve expat | mkarabulut|
————————————
| 2 | html ve table| TheBozo |
————————————-
| 3 |Raistin klav..| Raist |
————————————-

1
mustafa
Karabulut

2
Hakan
Müstak

1
php ve expat
mkarabulut

2
html ve table
TheBozo

3
Raistin klav..
Raist

Yukarıda görüldüğü gibi veritabanımızı XML olarak dump etmek için bize gerekenler şunlardır :

* 1- DVeritabanı adı (Root node olarak)
* 2- Tablo isimleri
* 3-Tablolarda bulunan alan (field) isimleri
* 4-Veriler,yani kayıtların kendileri

Programcının yapması dikkat etmesi gereken noktalar :

* 1- DVeritabanı adı (Root node olarak)
* 2- Tablo isimleri
* 3-Tablolarda bulunan alan (field) isimleri
* Tablo içindeki kayıtlar mysql den alınacak
* Bir sorgu ile de tablo içindeki alan isimleri alınacak
* Tablo ismi etiketi içinde her kayıt döngü içinde XML dok. dönüştürülücek

Veritabanı içindeki tabloların listesi :

Bir veritabanı içindeki tabloların listesini almak için 2 yolumuz var.
Birinci yol PHP’nin mysql_list_tables($dbname,$conn) fonksiyonunu kullanmak : Bu fonksiyon varolan bir veritabanı bağlantısı bilgisini ve veritabanı ismini alır ve veritabanındaki tablo bilgilerini mysql result bilgisi olarak geri dönderir.Sonuçları almak için mysql_result() veya mysql_fetch_array() gibi fonksiyonlar kullanılmalıdır.

İkinci yol ise mysql sorgusu kullanarak öğrenmektir : Yapacağımız işlem “SHOW TABLES” sorgusunu veritabanına göndermektir.Örneğin :

<?
$conn=mysql_connect ($localhost,$user,$password);
mysql_select_db($database,$conn);
$sorgulama=mysql_query(“SHOW TABLES”);
while ($kayit=mysql_fetch_array($sorgulama))
echo “Tablo :”.$kayit[0].”
“;
mysql_free_result($sorgulama) ;
?>

Biz class yapısı içinde daha doğal bir yöntem olan 2. metodu kullandık.

Tablo alan isimlerinin alınması :

Bir tablo içindeki alanların alınması,mesela yukarıdaki uyeler tablosu için uye_id,isim,soyisim şeklinde olan alan isimlerinin alınması işlemi için yine 2 ayrı metod kullanılabilir.
Birinci metod yine PHP’nin bir fonksiyonu olan mysql_list_fields($dbname,$tablename,$conn) fonksiyonunu kullanmak: Bu fonksiyon aldığı 3 parametre ile sırasıyla veritabanı adı,tablo adı ve bağlantı bilgisini alır. Geriye mysql_result(),mysql_fetch_array() gibi fonksiyonlar tarafından alınabilecek sonuç bilgisi dönderir.

İkinci yok ise yine mysql’in sağladığı sorguları kullanmaktır : Bu sefer kullanacağımız sorgu “SHOW FIELDS FROM tablo” dır.

<?
$conn=mysql_connect ($localhost,$user,$password);
mysql_select_db($database,$conn);
$sorgulama=mysql_query(“SHOW FIELDS FROM uyeler”);
while ($kayit=mysql_fetch_array($sorgulama))
echo “Alan ismi :”.$kayit[0].”
“;
mysql_free_result($sorgulama) ;
?>
Yine class yapisinda 2. metodu kullandik.
?>

Böylece veritabanı içindeki tabloların ve tablo alanlarının isimlerini nasıl alınabileceğini görmüş olduk. Geriye son adım olarak kayıtların alınması kalıyor, o da çok aşina olduğumuz “SELECT * FROM tablo” sorgusu ile yapacağımız bi işlemden ibaret. Kod sırasında dikkat etmemiz gereken nokta döngüleri doğru kurarak , tabloları listelemek, tablolar listelenirken kayıtları ve alan isimlerini alarak XML dokumanını döngüler içinde oluşturabilmektir.

Class yapısını inceleyip metodları ve özellikleri üzerinde konuşmaya başlamadan önce genelde bilinen fonksiyonlar kullanmama rağmen 2 tane yeni olabilecek fonksiyondan bahsetmek istiyorum :

$number= count($degisken) : count() fonksiyonu kısaca verilen dizi değişken gibi bir değişkenin eleman sayısını geri dönderir. Örneğin

İkinci fonksiyon ise number_format fonksiyonu() :Verilen bir sayısı binler basamağı,ondalıkları gibi bilgileri istenilen gibi düzenlenerek formatlayıp geri döndürür. Fonksiyonun paramereleri
number_format ($sayi,$ondalik_sayisi,$ondalik_ayrac_stringi,$binler_ayrac_stringi);
Örnek kullanım

Şimdi scriptimize geçebiliriz. Class dosyamızın adı mysql2xml…

mysql2xml class yapısı :

mysql verisini well-formed bir xml dokumanına dönüştüren class’ın tam kodu şu olacaktır.

conn = $conn;
$this->listalltables=$lallt;
$this->tablename=$tbl;
$this->encoding=$e;
$this->db=$db;

$this->dumpdb();
} // function mysql2xml

function dumpdb(){

if ($this->listalltables){
$q=”SHOW TABLES”;
$query=mysql_query($q,$this->conn);
if (mysql_num_rows($query)>0){
while($record=mysql_fetch_array($query))
$table[]=$record[0];
} else {
$table=array();
}
mysql_free_result($query);
} else {
$table[]=$this->tablename;
}// if $this->listalltables

//xml dosyasını oluştur
$tarih=date(“H:i:s d/m/Y”);
$xml = “encoding.”\”?>\n”;
$xml.= “db\n”;
$xml.= “–>\n”;
$xml.= “db>\n”;

$this->stats["Tablo sayısı"]=count($table);
$this->stats["Kayıt sayısı"]=0;
for ($i=0;$iconn);
$this->stats["Kayıt sayısı"]+=mysql_num_rows($query);
if (mysql_num_rows($query)>0){
// alanların isimlerini al
$xml.=”";
$q=”SHOW FIELDS FROM “.$table[$i];
$query2=mysql_query($q,$this->conn);

while($fi=mysql_fetch_array($query2))
$fields[]=$fi[0];

mysql_free_result($query2);

while($record=mysql_fetch_array($query)){
$xml.=”\n”;
foreach ($fields as $field){
$xml.=”";
$xml.=$this->tidy(@$record[$field]);
$xml.=”\n”;
}
$xml.=”\n”;
}
} // if mysql_num_rows

mysql_free_result($query);
} //for

$xml.= “db>”;

$this->stats["XML karakter sayısı"]=number_format(strlen($xml),0);
$this->xml_output=$xml;
} // function dumpdb

function tidy($str){
// ,& ler temizleniyor
$str = str_replace(“&”,”&”,$str);
$str = str_replace(“”,”>”,$str);
return $str;
}

function xml_output(){
return $this->xml_output;
}

function stats(){
$str = “

mysql dump istatistikler

“;
foreach ($this->stats as $name=>$value){
$str.=”

  • $name : $value”;
    }
    return $str;
    }
    } // class mysql2xml

    ?>
    Sınıf yapısı içinde bulunan metodlar,özellikler ve class’ın kullanımı hakkında biraz açıklama yapalım, diğer sayfadan devam etmeden biraz dinlenin sonra sınıf yapısını baştan aşağıya biraz inceleyip anlamaya çalışın, eğer biraz üzerine yoğunlaşabildiyseniz diğer sayfadaki açıklamalarla yapıyı tamamen çözebileceksiniz. Devam edelim…
    Burada tek belirtmek istediğim veritabanından kayıtlar okunupda içerikleri #PCDATA olarak XML dokumanına yazılırken doğrudan yazılmaz önce sınıf içindeki tidy() metoduna gönderilirler. Bunun sebebi şudur :
    XML dokumanında #PCDATA encoding ile belirtilen karakter setindeki tüm karakterleri kabul edebilir ama 3 karakter istisnadır.
    Bunlar
    & ,
    karakterleridir. Onun için veritabanından alınan veri önce tidy() metoduna gönderilip bu metod içinde bu karakterleri zararsız hale getirir.

    tidy() metodu : Bu metodun tek yaptığı iş string içindeki &, karakterlerini bulup bunları sırasıyla " < > ile değiştirmektir. Böylece XML dokumanının well-formed özelliğini bozabilecek bu karakterlerde gerektiği şekilde dokumana eklenmiş olur.

    Sıradaki metodumuz ise xml_output() metodudur: Bu metod çok basit olarak dbdump() sırasında oluşturulup $xml_output özelliğine atılan XML dokumanını string olarak geri dönderir.

    Son metodumuz ise stats() metodudur : Bu metod dbdump() sırasında veritabanında bulunan tablo sayısı, kayıt sayısı ve oluşturulan XML dokumanının karakter sayısı gibi istatistiksel bilgileri sınıfın $stats özelliğini okuyarak ekrana yazdırır.

    Sınıfımızı anlattıktan sonra bir de örnek kullanım göstermemiz gerekiyor sanırım :

    stats();
    //ekrana xml verisini yazdir
    echo $xml_dump->xml_output();
    ?>

    Böylece basit bir şekilde mysql verisini xml’e atan bir sınıf yazdık ve başarıyla çalıştırdık. Ama muhtemelen sınıfı kullanırken siz xml verisini doğrudan ekrana yazmak istemeyebilir onu bir dosya olarak kaydetmek isteyeceksinizdir. yapacağız işlem boş bir dosya oluşturup, içeriği fwrite ile yazmaktan ibaret…

    xml_output(),$fhand);
    fclose($fhand);
    ?>

    Tüm işlemleri böylece bitirmiş olduk, tekrar biraz dinlenin ve diğer sayfada sınıf yapısının eksikleri, geliştirilmesi gereken noktaları ve geneli hakkında bir sonuç ile yazımızın bu ilk kısmını bitirelim…

    Sonuç :

    Aslına bakılırsa mysql’in son versiyonları veritabanı yapısını well-formed xml olarak dump etme özelliğini destekliyor, yani basitçe komut satırından

    c:\mysql\bin>mysql –xml veritabani_adi > dump.xml

    komutu ile bu işlemi yapabiliriz. phpMyadmin’in son sürümleride veritabanının istenilen tablolarını xml olarak verme özelliğine sahip. Peki biz neden bu kadar uğraştık ? Öncelikle yazıdaki amacımız öğrenmekti. Mesela

    1. 1- XML dokumanlarına daha çok haşır neşir olmayı, çünkü XML dokumanlarını her ne kadar mysql,SQL server bize XML olark verse de onları parse edecek, işleyecek scriptleri yine biz yazacağız. Bu yüzden XML dokumanlarının yapısını ve bu işin mantığını iyi öğrenmemiz gerekiyor.
    2. 2- Bu yazı ile bir kaç yeni mysql sorgusu kullandık, mesela “SHOW TABLES”, “SHOW FIELDS FROM tablo” gibi.
    3. 3- Bir kaç yeni php fonksiyonu kullandık, count(), number_format() gibi..
    4.
    4- OOP’yi ciddi bir örnek üzerinde çalışırken gördük.

    Bu scriptimiz ile yeni şeyler öğrenmiş olmamamıza ve scriptin genel olarak işini düzgün yapıyor olmasına rağmen sınıf yapımızın bazı eksikleri ve geliştirilmesi gereken yönleri var.

    Öncelikle şunu söyleleyim, mysql2xml class’ı her ne kadar basit de olsa aslında bir API olabilir. Ama her API de olması gereken hata kontrolü gibi temel bir özellikten yoksun… Çok basit olarak bu özelliği de ekleyebiliriz. Yapmamız gereken temel olarak
    $error isimli bir özellik ve
    error_exists(), get_last_error(), get_all_errors() gibi metodlar eklemek. Böylece hem API’yi kullanan programcı hemde sınıf metodları hata kontrollerini yapabilecekler. Özellikle sınıf metodlarının sınıfın kendi hata kontrol yapılarını kullanması,metodların hata durumlarında çalışmalarını kontrol ederek istenmeyen sonuçlar çıkarmalarına engel olur.

    Bir değineceğimz nokta ise veritabanının yapı bilgisinin tam olarak XML dokumanı içinde tutulmaması ile ilgili. phpmyadmin’den hatırlarsının veritabanı dökümünü verirken istersek bize yapı ve veriyi içeren bir döküm dosyası verebiliyordu. Gerçi XML açısından işler biraz daha değişik olmasına rağmen bir şekilde yapı bilgisini de XML dokumanı içerisine gömebilirdik. Genede oldukça karmaşık bir durum söz konusu :

    1. 1- XML dokumanları sistemleri arası verilerin paylaşımı için geliştirilmiştir. Dolayısıyla ‘auto_incement’ alan bilgisi sadece mysql için tanımlı olduğundan diğer sistemler için tanımsız olacaktır. Daha doğrusu XML dokumanı içerisinde gereksiz yer işgal edecektir.
    2. 2- XML içindeki mysql veriyapısı bilgisini yine sadece mysql sistemleri kullanabilecektir. Peki text dosyalara dump etme özelliği varken, neden XML kullanalım o zaman?

    Yinede sınıf yapısı içine isteğe bağlı olarak,parametrelerle belirlenecek şekilde yapı-veri, sadece veri, sadece yapı gibi ayrı ayrı dump seçenekleri koymanın da pek zararı olmaz heralde :-)

    Bir eklenebilecek özellik ise CSS, XSL gibi şeyler kullanarak XML dokumanını biraz daha human readable yani daha anlaşılır bir hale dönüştürmek olabilir. Dokumana eklenecek XSL dönüşümleri ile veritabanı yapısı bir tablo halinde HTML formatında görünse fena olmaz heralde?

    Böylece mysql’den XML’ye veri dump etme işlemini de incelemiş olduk. Daha geliştirilmeye açık bir sınıf yazdık ve çalıştırdık, elimizde şu an için bir XML dosyamız olmuş oldu. Sıra geldi şimdi bu dosyası okuyacak, işleyecek ve mysql’e tekrar atacak scripti yazmakta…

    Hala devam etmekte kararlıysanız ve yorgun değilseniz xml2mysql sınıf yapısını yazmaya başlayalım… Yazının devamı MySQL XML Dump-II’de

  • Yorum bırakın »