Blog okuyucularımdan biri elindeki XML verisini Oracle’a nasıl aktaracağını sordu. Oracle’da XML Type oluşturulabildiğini ve bu veri üzerinde XPath, XQuery sorgularının yapılabildiğini biliyordum ama verinin direk olarak bir tabloya aktarılmasını denememiştim.
Hemen kolları sıvayıp bunun üzerine bir yazı hazırlamaya başladım. Pazar günü yazıyı hazırlamış olmama karşın, iş nedeniyle şehir dışına çıkmam yüzünden temize çekip yayınlamak bu güne kaldı. Şimdi örnek bir XML dosyasını adım adım tablomuza aktaralım:
Öncelikle bir örnek XML dosyasına ihtiyacımız olacak. Ben şu dosyayı oluşturdum:
<MUSTERILER>
<MUSTERI>
<NO>1</NO>
<ISIM>Gökhan</ISIM>
</MUSTERI>
<MUSTERI>
<NO>2</NO>
<ISIM>Ümit</ISIM>
</MUSTERI>
<MUSTERI>
<NO>3</NO>
<ISIM>Yusuf</ISIM>
</MUSTERI>
<MUSTERI>
<NO>4</NO>
<ISIM>Nedim</ISIM>
</MUSTERI>
<MUSTERI>
<NO>5</NO>
<ISIM>Cüneyt</ISIM>
</MUSTERI>
</MUSTERILER>
Aslında Oracle, tabloya aktarılacak XML dosyalarında “root” element olarak ROWSET ve her kayıdın ROW olarak tanımlanmasını bekliyor. Yani bizim örnek dosyamızın şu şekilde olmasını istiyor:
<ROWSET>
……
<ROW>
<NO>1</NO>
<ISIM>Gökhan</ISIM>
</ROW>
…..
</ROWSET>
Ama biz bu çevrimi yapmak zorunda değiliz, aktarım sırasında Oracle’a her kayıdın ROW yerine MUSTERI tagi ile ayrıldığını söylememiz yeterli olacak. Yalnız çok önemli iki nokta var: Birincisi tabloya aktaracağımız XML dosyasının dili veritabanımızın diline uygun olmalı, ikincisi XML TAG’leri büyük harflerle yazılmış olmalılar, yoksa tablodaki kolonlarla otomatik eşleştirme yapılamıyor. Bu durum aktarımın yapılamayacağı anlamına gelmiyor, yalnız böyle bir durumda anlatacağım kolay aktarım yöntemi yerine bizim XML’i parse edecek kod yazmamız gerekiyor.
Örnek XML dosyası oluşturduktan sonra, bu XML dosyasını aktaracağımız bir tablo oluşturabiliriz. Örnek verilerden anlaşılacağı üzerine tablomuzda “NO” ve “ISIM” olarak adlandırılmış iki kolon olması yeterli:
SQL> CREATE TABLE musteri( no NUMBER, isim VARCHAR2(50 ));
XML dosyasını veritabanı tarafından okunabilmesi için, bulunduğu dizini gösteren bir directory objesi oluşturuyoruz.
SQL> CREATE DIRECTORY C AS ‘C:\’;
Aktarma işlemi için herşey hazır. Şimdi kısa bir PL/SQL bloğu yazıp önce XML dosyamızı geçici olarak oluşturacağımız bir CLOB objesi içine aktaracağız, daha sonra da DBMS_XMLSTORE paketinindeki fonksiyonları kullanarak CLOB içindeki XML verisini tablomuza aktaracağız:
DECLARE
xml_handle DBMS_XMLSTORE.ctxtype;
dosya BFILE;
kayit_sayisi NUMBER;
xml_data CLOB;
BEGIN
dosya := BFILENAME ( ‘C’, ‘musteri.xml’);
DBMS_LOB.createtemporary (xml_data, TRUE, DBMS_LOB.SESSION);
DBMS_LOB.fileopen (dosya, DBMS_LOB.file_readonly);
DBMS_LOB.loadfromfile (xml_data, dosya, DBMS_LOB.getlength (dosya));
DBMS_LOB.fileclose (dosya);
xml_handle := DBMS_XMLSTORE.newcontext (‘HR.MUSTERI’);
DBMS_XMLSTORE.setrowtag (xml_handle, ‘MUSTERI’);
kayit_sayisi := DBMS_XMLSTORE.insertxml (xml_handle, xml_data);
DBMS_XMLSTORE.closecontext (xml_handle);
DBMS_LOB.freetemporary (xml_data);
END;
/
Dosya okuma işini DBMS_LOB, aktarma işlemini DBMS_XMLSTORE paketinini kullanarak yapıyoruz. Oracle’ın XML ile ilgili bir çok paketi var, ama ben DBMS_XMLSTORE’u kullanmayı tercih ettim. DBMS_XMLSTORE.setrowtag ile her kayıdın “MUSTERI” tagi ile ayrıldığını belirttiğime dikkat edin. Eğer isterseniz “kayit_sayisi” değişkeninin içeriğini kontrol ederek XML verisinden tabloya kaç kayıt aktarılmış öğrenebilirsiniz.
Dosyaları yazıdan kopyalayıp yapıştırınca, wordpress’in yazılar üzerinde yaptığı değişiklikler yüzünden hatalar alabilirsiniz. Bu yüzden oluşturduğum örnek XML’i ve PL/SQL kod bloğunu download edebilmeniz için zipledim: [download#3#size#nohits]


23 Ocak 2009
Hocam emeğine sağlık çok yararlı oldu, tekrardan çok teşekkür ederim.
Vaktiniz olursa Pl/SQL “static ve dinamik sql”ler hakkında bir yazı hazırlayabilir misiniz, merakla bekleyeceğiz… Şimdiden çok teşekkür ederim
11 Şubat 2009
Çok teşekkür ederim yararlı bilgileriniz için.
3 Ağustos 2009
Gokhan bey,
burada anlatdiginiz gibi yaptigimda DBMS_LOB.fileopen fonsiyonunda error veriyor.
DECLARE
xml_handle DBMS_XMLSTORE.ctxtype;
dosya BFILE;
kayit_sayisi NUMBER;
xml_data CLOB;
BEGIN
dosya:= BFILENAME(‘xml_dir’,'musteri.xml’);
DBMS_LOB.createtemporary(xml_data,TRUE, DBMS_LOB.SESSION);
DBMS_LOB.fileopen(dosya,DBMS_LOB.file_readonly);
DBMS_LOB.loadfromfile(xml_data,dosya,DBMS_LOB.getlength(dosya));
DBMS_LOB.fileclose (dosya);
xml_handle := DBMS_XMLSTORE.newcontext (‘SYS.MUSTERI’);
DBMS_XMLSTORE.setrowtag (xml_handle, ‘MUSTERI’);
kayit_sayisi := DBMS_XMLSTORE.insertxml (xml_handle, xml_data);
DBMS_XMLSTORE.closecontext (xml_handle);
DBMS_LOB.freetemporary (xml_data);
END;
ORA-22285: non-existent directory or file for FILEOPEN operation
ORA-06512: at “SYS.DBMS_LOB”, line 523
ORA-06512: at line 9
2 gundur neden bu hatayi verdiyini arastiriyorum, ama bir sonuca ulasmis degilim. Yardim ederseniz sevinirim.
Saygilarimla.
4 Ağustos 2009
Shappy,
xml_dir directory’sini tanımlamadığınızdan hata alıyorsunuz:
SQL> CREATE DIRECTORY C AS ‘C:\’;
satırında (bu arada sayenizde yazım hatası yaptğımı gördüm), C diye bir dizin tanımlayıp ondan sonra o dizindeki XML dosyasını açıyoruz. Sizin de aynı şekilde bir XML_DIR tanımlamanız gerekiyor. Bu arada dizin ismini büyük harfle yazın, Oracle’da obje isimleri özellikle belirtilmediği sürece büyük harf olarak tutulur:
dosya:= BFILENAME(’XML_DIR’,’musteri.xml’);
Kolay gelsin
Gökhan