Mostani részben szeretném megismertetni az olvasókat az első olyan megjelenítési formával, ahol az XML adatok egy HTML oldal segítségével kerülnek megjelenítésre. Ezen megoldás egy DSO (Data Source Object) objektumot használ, mely segítségével az XML adatok a HTML oldalba vannak illesztve és ezen belül HTML elemekhez vannak kötve. Innen is ered az adatkötés technika megnevezés. A cikksorozat ezen része egy kicsit eltér az eddig megszokottaktól, mivel röviden szeretnék egy másik a Microsoft által kifejlesztett külső adattárolási technológiát is bemutatni, a TDC-t.

Adatkötéses technikák keletkezése és értleme

Napjainkban egyre nagyobb az internetes oldalak adatigénye, ami az oldal és egyben adat frissítéseket nagyban megnehezíti. A web oldalak túlnyomó része adatbázisból dolgozik, vagyis a gyakran változó adatok egy szerveren lévő adatbázisban vannak tárolva. A megoldás lényege és egyben legnagyobb előnye a nagyon gyors adatfrissítés lehetősége. A szerver oldali adatbázis hátránya, hogy nagyban igénybe veszi a szerver erőforrásait, mivel minden egyes kliens oldal felől érkező kérés esetén az egész oldal újra előállításra kerül az adatok alapján.

Rögtön vegyünk egy példát az érthetőség kedvéért! Tételezzük fel, hogy van egy adatbázisból dolgozó oldalunk, amely tartalmazza az eddigi forma1-es világbajnokok listáját. A lista tartalmazza az évet, a pilóta nevét és nemzetiségét. A felhasználóknak lehetőségük van a listát név, évszám és nemzetiség szerint rendezni, illetve egy bizonyos nemzetiségű világbajnokokat kiiratni. Amikor az egyes csoportosítási funkciók közül válogatnak, a szerver mindig ugyanazon lista ugyanazon elemeit, részelemeit küldi el nekünk. Ez egy csomó felesleges "munka" a szervernek, főleg ha belegondolunk abba, hogy egyidejűleg több tíz, vagy akár ezer ember is kíváncsi ugyanezen adatokra.

Mindenkiben felmerül a kérdés: Vajon hogyan lehetne megoldani ezt az elég fontosnak tűnő problémát? Ezen probléma (részleges) megoldására fejlesztettek ki egy elegáns technológiát, az úgynevezett adatkötéses technológiát. Ez a technológia lehetővé teszi az adatok helyi tárolását a HTML kódtól elkülönítve. Az úgynevezett adatforrás objektumok (Data Source Object) segítségével a web oldalunk a külső adatok számára egyfajta megjelenítő sablonként fog működni. Eme technológia egyik legnagyobb előnye a szerver terhelésének csökkentése az adatok aktualizálásánál, illetve az adatokkal való munka során.

Akkor most lássunk, hogy is működik ez a valóságban: A felhasználó elküldi a kérését a szerver felé egy HTML űrlap segítségével. A szerveren lévő (szerveroldali) szkript (PHP, ASP, CGI, ISAPI) a felhasználói kérés alapján az adatbázisból kigenerálja a kívánt adatokat és elküldi a felhasználónak (pl. XML formájában). Az összes többi műveletet ezen adatokkal a kliens oldal végzi a DSO objektumokon keresztül. SKicsit visszakanyarodva a példánkhoz: A felhasználó tehát szeretné megtekinteni a forma1 történetének összes vilagbajnokát. Elküldi a szervernek a kérést, a szerver előállítja a megjelenítési sémát, vagyis a HTML forrást és külön a puszta adatokat. A kliens oldal értelmezi a kapott adatokat és a DSO-n keresztül kitölti a HTML oldalt. Ha rendezni, illetve válogatni akarunk az adatok között, akkor az csakis a kliens oldalon történik a DSO-n keresztül.

A DSO használatának hátrányai közé tartozik, hogy rögtön az elején le kell tölteni a kliens oldalra az összes adatot (igaz, ez a probéma kiküszöbölhető az aszinkron adat feldolgozás használatával), az adatoknak szimmetrikusaknak kell lenni és a DSO-nak a gépünkön kell lenni.

DSO hatáskörébe tartoznak:

  • hogyan lesznek az adatok továbbítva szerver-től kliens-ig (pl. HTTP protokoll segítségével)
  • milyen műveleteket tudunk végezni az adatokkal (pl. rendezés, válogatás, frissítés)
  • hogyan vannak az adatok tárolva (pl. szöveges fájl)
  • milyen lesz az objektum modell (DOM) az adatok hozzáférésénél
Az Internet Explorer (IE) tartalmaz néhány beépített DSO-t, de lehetőség van saját DSO objektumok létrehozására is, például C vagy Java nyelvek segítségével. A DSO-tól kapott adatok feldolgozhatóak szkriptek segítségével (pl. JavaScript), vagy közvetlenül beépíthetőek a HTML oldalba a HTML által nyújtott kiegészítő elemek segítségével.

Az IE-ben található DSO objektumok:

  • Remote Data Service - lehetőséget ad az adatokkal való műveletek végzésére és aktualizálására bármilyen OLE DB kompatibilis szolgáltatóval
  • applet JDBC - Netscape Navigator-ban is támogatott DSO, de a hozzáférés csak szkriptek segítségével lehetséges
  • Tabular Data Control - szöveges fájl az adatforrás, nem lehet adatokat frissíteni a szerveren
  • XMLDSO - XML adatokat értelemző DSO
Ahhoz, hogy az adatainkhoz hozzá tudjunk férni, szükséges, hogy a DSO valamilyen formában a gépünkön legyen (pl. ActiveX komponens, Java Applet). Ha mindez megvan, akkor az adatok az úgynevezett adat befogadó és az összekötő ágens segítégével megjeleníthetőek.

Az összekötő ágens irányitja és szinkronizálja az adatfolyamot a DSO és adatbefogadók között.

Tehát vegyük szépen át az egész folyamatot az elejétől: Első lépésként kell nekünk egy HTML oldal, amelybe beillesztjük a külső adatokat. Az adatok beillesztése történhet közvetett(az adatok egy külső fájlban vannak) vagy közvetlen(az adatok egyenesen a HTML kódba vannak implementálva [ez csak XMLnél használható TDCnél nem]) módon.

Miután a külső adatokat sikeresen hozzákapcsoltuk a dokumentumunkhoz (HTML), a böngésző létrehozza a DSO objektumot, amely automatikusan értelmezi a külső adatokat és hozzáférhetővé teszi azokat (úgynevezett rekordokat hoz létre). Ezek után, ha egy HTML elem tartalmaz adatkötést akkor a DSO objektum automatikusan betölti oda az adatot (vagy adatokat, attól függően, hogy milyen elemről van szó).

Adatok beillesztése a HTML dokumentumba

Az adatok beillesztése a HTML dokumentumba az úgynevezett adatsziget segítségével történik. XML esetében ez nem más mint az <XML></XML> TAG. Ezen TAG két jellemzőt támogat:

  • ID - amely azonosítja az adatszigetet
  • SRC - hivatkozik a külső fáljra, amelyben vannak a tényleges XML adatok
Amennyiben közvetlenül szeretnénk megadni az adatokat, vagyis az XML forrást, úgy rögtön írhatnánk az XML forrást az <XML> TAG-on beülre. Ezen megoldás használata nem igazán ajánlott. Az általános és javallott megoldás a közvettet adatmegadás, melynél csak hivatkozunk a külső fáljban tárolt XML adatokra, méghozzá úgy, hogy a SRC jellemző értékéül megadjuk a fájl elérési útvonalát.
<HTML> <HEAD><TITLE>Adatsziget</TITLE></HEAD> <BODY> <!--      közvetlen adatmegadás       -->    <XML ID="közvetlenDSO1">      <?xml version="1.0" encoding="ISO-8859-2"?>      <F1VILAGBAJNOKOK>        <F1VILAGBAJNOK>          <EV>1954</EV>          <NEV>Juan Fangio</NEV>          <NEMZETISEG>Argentin</NEMZETISEG>        </F1VILAGBAJNOK>        <F1VILAGBAJNOK>          <EV>1955</EV>          <NEV>Juan Fangio</NEV>          <NEMZETISEG>Argentin</NEMZETISEG>        </F1VILAGBAJNOK>        <!-- ... -->      </F1VILAGBAJNOKOK>    </XML>     <!--      közvetett adatmegadás       -->    <XML ID="közvetettDSO2" SRC="f1_vilagbajnokok.xml"></XML> </BODY> </HTML>
A fenti példánkban bemutatásra került mindkét adatbeillesztési megoldás. Egyenlőre még nem történik semmi sem az adatokkal, a megjelenítést illetően. Amennyiben a későbbiekben hozzá szeretnénk férni az adatainkhoz, úgy ne feledkezzünk meg az azonosító megadásáról, amelyet az ID jellemző értékéül kell megadnunk, és amelynek egyedinek kell lenni.
Adatbefogadók

Adatbefogadó komponenseknek nevezzük azon elemeket, amelyek a DSO által szolgáltatott adatokat megjelenítik. Ezek lehetnek az általános HTML komponensek (pl. SPAN, DIV, TABLE) vagy az ActiveX, illetve Java Applet külső objektumai. Az adatbefogadók kiválasztása nagyban függ a megjeleníteni kívánt adatok struktúrájától (DIV,SPAN - csak egyetlen adat megjelenítésére képes, ellenben a TABLE elemmel, amely egy adatforrás több elemét is képes megjeleníteni ).

Mit is jelent ez pontosan? Amennyiben egy olyan elemhez rendelünk hozzá adatot, amely több rekordot is képes megjeleníteni (pl. TABLE), akkor a DSO megjeleníti az összes rekordot, úgy, hogy sokszorozza pl. egy táblázat esetén a sorokat. Egy egyrekord megjelenítésére alkalmas elem esetén (pl. SPAN) csak az első rekord kerül megjelenítésre.

Az IE tartalmaz néhány HTML-elem tulajdonságot a DSO által szolgáltatott adatok befogadására:

  • DATASRC tulajdonság azonosítja a DSO objektumot (a DSO objektum ID-jét tartalmazza)
  • DATAFLD tulajdonság azonosítja a DSO adatainak egyik oszlopát
  • DATAFORMATAS tulajdonsággal adhatjuk meg, hogy az elem tartalma szöveg vagy esetleg HTML kód
  • DATAPAGESIZE tulajdonság adja meg az elemek számát egy oldalon (csakis többrekord megjelenítésére alkalmas elemeknél használható)
Következőkben ismerkedjünk meg néhány elemmel, amelyek képések a DSO által szolgáltatott adatok megjelenítésére:
Elem Értlemezi a HTML jelöléseket Frissíti az XML mező tartalmát
A Nem Nem
DIV Igen Nem
FRAME Nem Nem
IMG Nem Nem
INPUT TYPE=button Igen Nem
INPUT TYPE=checkbox Nem Igen
INPUT TYPE=password Nem Igen
INPUT TYPE=radio Nem Igen
INPUT TYPE=text Nem Igen
SELECT Nem Igen
SPAN Igen Nem
TEXTAREA Nem Igen

Miről is van szó? A fenti táblázatban a DSO által szolgáltatott adatok megjelenítését támogató elemek két lényeges tulajdonságát tüntettük fel, mégpedig azt, hogy amennyiben HTML elemeket használunk az XML mező szöveges tartalmaként, úgy azt képes e az adatbefogadó értelmezni, illetve amennyiben megváltoztatjuk az adatbefogadó tartalmát, úgy az eredeti XML tartalom is frissül e. Ezeket rögtön be is mutatjuk egy példán, de mindezek előtt tanuljuk meg az DSO rekordjait HTML elemekhez kapcsolni.

egyszeruDSO.htm

<HTML> <HEAD> <TITLE>Egyszerű DSO</TITLE> <XML ID="oDSO" SRC="f1_vilagbajnokok.xml"></XML> </HEAD> <BODY> <B>Év</B>: <SPAN DATASRC="#oDSO" DATAFLD="EV"></SPAN><BR> <B>Név</B>: <SPAN DATASRC="#oDSO" DATAFLD="NEV"></SPAN><BR> <B>Nemzetiség</B>: <SPAN DATASRC="#oDSO" DATAFLD="NEMZETISEG"></SPAN><BR> </BODY> </HTML>     
Megszületett az első olyan HTML oldalunk, melyen a DSO objektum által szolgáltatott XML adatok vannak megjelenítve. A megjelenítéshez SPAN elemeket használtunk fel, melyeknek megadtuk a forrást, vagyis a DSO objektum ID-jét, valamint a megjeleníteni kívánt mező vagy rekord nevét a DATAFLD jellemző értékeként. Ezen megoldástól egy lépcsőfokkal nehezebb a rekordhalmaz megjelenítése. Ezen cél eléréséhez a TABLE elemet hívjuk segítségül.

rekordhalmazDSO.htm

<HTML> <HEAD> <TITLE>Rekordhalmaz megjelenítése</TITLE> <XML ID="oDSO" SRC="f1_vilagbajnokok.xml"></XML> </HEAD> <BODY> <input type="button" value="<< első oldal" onClick="table.firstPage()"> <input type="button" value="< előző oldal" onClick="table.previousPage()"> <input type="button" value="következő oldal >" onClick="table.nextPage()"> <input type="button" value="utolsó oldal >>" onClick="table.lastPage()"> <TABLE DATASRC="#oDSO" DATAPAGESIZE="10">    <THEAD>     <TR>       <TD width="70"><B>Évszám</B></TD>       <TD width="150"><B>Versenyző neve</B></TD>       <TD><B>Nemzetiség</B></TD>     </TR>   </THEAD>     <TR>       <TD bgcolor="silver"><SPAN DATAFLD="EV"></SPAN></TD>       <TD bgcolor="gray"><SPAN DATAFLD="NEV"></SPAN></TD>       <TD bgcolor="silver"><SPAN DATAFLD="NEMZETISEG"></SPAN></TD>     </TR> </TABLE> </BODY> </HTML>
Tehát a TABLE elem nyitó részében megadtuk a DSO objektum forrását, ezen kívül meghatároztuk, hogy maximum 10 elem jelenjen meg egyszerre (DATAPAGESIZE="10"). Ezek után viszont egy érdekes problémába ütközünk: Hogyan rendeljük hozzá az egyes mezőket a táblázat egyes oszlopaihoz, mivel az gondolom mindenkinek feltűnt, hogy az adatbefogadó elemek listájában nem szerepel a TD elem. Ezért van szükség a SPAN elem használatára, mely csak annyiban tér el az egy rekord megjelenítésénél használt megoldástól, hogy nem kell megadni az adatforrás objektumot.

Amennyiben elhagyjuk a TABLE elem nyitórészéből a DATAPAGESIZE jellemzőt, úgy az összes rekord megjelenítésre kerül. Viszont, ha bekorlátozzuk a megjeleníteni kívánt rekordok számát, kihasználhatunk egyet a DSO nyújtotta lehetőségek közül, a lapozást. Ehhez nem kell mást tennünk, mint ID-t adni a táblázatnak (melyel majd a későbbiekben hivatkozni tudunk rá) és valamilyen esemény bekövetkezésekor hivogatni az adatbefogadó táblázat következő metódusait:

Metódus Leírás
firstPage() az első rekordlapot jeleníti meg
previousPage() az előző rekordlapot jeleníti meg
nextPage() a következő rekordlapot jeleníti meg
lastPage() az utolsó rekordlapot jeleníti meg

Ahogy az a pédlaprogramból is látszik, mi egy gomb onClick eseményéhez (ez az esemény akkor következik be, amikor a felhasználó a bal egérgombbal ráklikkel a gombra) rendeltük hozzá a metódusokat (onClick="table.firstPage()").

Ezidáig egyetlen adatkötéshez használható jellemzőt nem mutattunk be, ez pedig a DATAFORMATAS jellemző. Jellemző alapértéke TEXT, amely mint szöveg értelmezi és jeleníti meg az XML elemek tartalmát. Viszont amennyiben mi HTML értéket adunk meg a DATAFORMATAS jellemzőnek, úgy az XML mező tartalmát HTML-ként értelmezi.

html_megjelenites.htm

<HTML> <HEAD> <XML ID="oDSO"> <?xml version="1.0" encoding="ISO-8859-2"?> <GYOKER> <![CDATA[     Ez egy <a href="#">hiperhivatkozás</a> <b>akarna</b> lenni!   ]]> </GYOKER> </XML> </HEAD> <BODY> Sima szöveg: <SPAN  DATASRC="#oDSO2" DATAFLD="$TEXT"></SPAN><BR> HTML: <SPAN  DATASRC="#oDSO2" DATAFLD="$TEXT" DATAFORMATAS="HTML"></SPAN> </BODY> </HTML>
A példaprogram egyetlen része szorul magyarázatra, mégpedig a $TEXT változó, mely a DSO egy speciális változója és az éppen aktuális elem (csakis) karakteres adatait tartalmazza. Mivel nekünk az aktuális elemünk maga a gyökérelem (GYOKER), melyet nem adhatunk meg a DATAFLD jellemzőnek, ezért használjuk a $TEXT változót, amely segítségével elérhettük az adatainkat.
Rekordokhoz való hozzáférés

Mint azt már említettük a DSO objektum rögtön rekordokba rendezi a betöltött adatokat, melyekhez különböző jellemzők és metódusok segítségével biztosít hozzáférést.

Metódus vagy jellemző Leírás
moveFirst() a rekordhalmaz első elemére állítja az elemmutatót
movePrevious() az előző elemre állítja az elemmutatót
moveNext() a következő elemre állítja az elemmutatót
moveLast() a rekordhalmaz utolsó elemére állítja az elemmutatót
move(Int i) a paraméterként megadott számot hozzáadja az elemmutatóhoz
String fields(String field) az aktuális elem paraméterként átadott mezőjének értékét adja vissza
addNew() új elemet ad a rekordhalmazhoz és ráviszi az elemmutatót
delete() törli az aktuális rekordot
cancelUpdate() visszavonja az aktuális elemen végrehajtott összes módosítást
Bool EOF jellemző értéke TRUE ha az utolsó utáni elemen van az elemmutató, ellenkező esetben értéke FALSE
Bool BOF jellemző értéke TRUE ha az első előtti elemen van az elemmutató, ellenkező esetben értéke FALSE
Int RecordCount az elemhalmaz hosszát tartalmazza
Int AbsolutePosition az aktuális rekord sorszámát tartalmazza

A fentebb táblázatba foglalt összes metódus, függvény és jellemző a DSO objektum recordset objektumának függvénye, metódusa vagy jellemzője, ami gyakorlatban annyit tesz, hogy a metódushívások a következő képpen néznek ki: oDSO.recordset.moveFirst(), ahol oDSO a DSO objektum ID-je.

Mielőtt még elkezdenénk örülni az addNew() és egyéb metódusok láttán, melyek segítségével a DSO adatai változtathatóak lennének, szögezzük le, hogy a DSO objektum a szerveren levő adatok másolataival dolgozik, nem pedig a valósakkal. Ezen függvények, metódusok, jellemzők és valamilyen kliens oldali szkriptnyelv segítségével számos fontos funkció megvalósítható, mint például a keresés, melyet hamarosan be is mutatunk, de előtte egy egyszerű kis példa az érthetőség kedvéért:

rekordhozzaferes_egyszeru.htm

<HTML> <HEAD> <TITLE>Egyszerű DSO</TITLE> <XML ID="oDSO" SRC="f1_vilagbajnokok.xml"></XML> </HEAD> <BODY> <B>Év</B>: <SPAN DATASRC="#oDSO" DATAFLD="EV"></SPAN><BR> <B>Név</B>: <SPAN DATASRC="#oDSO" DATAFLD="NEV"></SPAN><BR> <B>Nemzetiség</B>: <SPAN DATASRC="#oDSO" DATAFLD="NEMZETISEG"></SPAN><BR> <input type="button" value="<< első rekord" onClick="oDSO.recordset.moveFirst()"> <input type="button" value="< előző rekord" onClick="if(!oDSO.recordset.BOF)oDSO.recordset.movePrevious()"> <!-- az előző elem hívása előtt ellenőrizni kell, hogy az aktuális elem nem e az első elem --> <input type="button" value="ugrás" onClick="i=window.prompt('Add meg az számot', '1');if(!isNaN(i))oDSO.recordset.move(Number(i))"> <!-- beolvasunk a felhasználótól egy karakterláncot, ellenőrizzük, hogy szám-e, és ha igen beállítjuk az elemmutatót --> <input type="button" value="következő rekord >" onClick="if(!oDSO.recordset.EOF)oDSO.recordset.moveNext()"> <!-- ugyanaz a helyzet mint, az előző elemnél csak itt az utolsót kell tesztelni --> <input type="button" value="utolsó rekord >>" onClick="oDSO.recordset.moveLast()"> </BODY> </HTML>
A példaprogramunkban az egyrekordos megjelenítési mód került bemutatásra úgy, hogy azt kibővítettük 5 funkcióval, melyek a rekordok közti mozgást teszik lehetővé. Az egyes funkciókat gombokhoz kapcsoltuk, viszont itt a hibák elkerülése érdekében pár dologra figyelnie kell a programozónak. Ilyen például az utolsó elem utáni moveNext() metódust hívása, mely programhibához vezetne.

Következőkben egy kicsit összetettebb példán szeretném bemutatni, hogy a DSO és kis kliens oldali szkript ötvözése mennyi lehetőséget rejt magában. A példaprogramban ismételten a forma 1 világbajnokait tartalmazó XML fájlunkat használjuk fel, melyet beépítünk az oldalba, majd kliens oldali JavaScript segítségével keresést teszünk lehetővé a felhasználó számára. A keresés történhet név, évszám és nemzetiség alapján egyaránt. Azon rekordmezőket, amelyekben megtaláltuk a keresett kifejezést, a már megszokott táblázatos formában fogjuk megjeleníteni, persze programból dinamikusan előállítva.

rekordhozzaferes_osszetett.htm

<HTML> <HEAD> <TITLE>Összetett rekordhozzáférés DSO</TITLE> <XML ID="oDSO" SRC="f1_vilagbajnokok.xml"></XML> <SCRIPT TYPE="text/javascript" LANGUAGE="JavaScript"> <!-- function create_row(ev, nev, nemzetiseg)  //a táblázat egy sorát hozza létre { var row = document.createElement("TR"),  //sor elem létrehozása      ev_cell = document.createElement("TD"), //sor celláinak létrehozása      nev_cell = document.createElement("TD"),      nemzetiseg_cell = document.createElement("TD"); ev_cell.innerText = ev;  //az egyes cellák szöveges tartalmának beállítása a paraméterek alapján nev_cell.innerText = nev; nemzetiseg_cell.innerText = nemzetiseg; row.appendChild(ev_cell); //az egyes cellákat hozzárendeljük a sorhoz row.appendChild(nev_cell); row.appendChild(nemzetiseg_cell); return row;  //a fügvény visszatérési értéke maga a sor objektum } function delete_all_rows(tbody)  //mielőtt az új keresési eredményeket kilistáznánk töröljük a régi sorokat a táblázatból { while(tbody.rows.length > 0)  //a ciklus addig ismétlődik, amíg a táblázat tartalmaz sorokat        tbody.deleteRow(0); } function find_str()  //ezen függvény végzi a keresést és az eredménykiiratást is { var str = document.getElementById("search_str").value.toLowerCase(),     //"befogjuk" a text mezőt, ahova a keresendő szót írtuk, kiolvassuk a tartalmát (a szöveget)     //és átalakítjuk csupa kisbetűre, ezzel elkerülve a keresés kis-nagybetű érzékenységét      rsearchfor = document.getElementsByName("rsearchfor"), //a három radio-button objektumot tartalmazza      searchfor = (rsearchfor[0].checked ? "nev" : (rsearchfor[1].checked ? "ev" : "nemzetiseg")),     //attól függően, hogy melyik radio gomb van bejelölve a searchfor változónak az értéke lehet: "nev", "ev", "nemzetiseg"     //későbbiekben ez fogja meghatározni, hogy a rekordhalmaz melyik mezőjében fogunk keresni      tbody = document.getElementById("list_tab"),     //a lista táblázatot test részére; ide hozzuk létre a sorokat      found = false; delete_all_rows(tbody);  //töröljük az összes létező sorát a táblázatnak oDSO.recordset.moveFirst();  //az első elemre állítjuk az elemmutatót while(!oDSO.recordset.EOF)  //a ciklus végigmegy a rekordhalmaz összes elemén       { if(oDSO.recordset(searchfor).value.toLowerCase().indexOf(str) !=-1) //minden rekord searchfor változóban tárolt nevű mezőjét   {  //átalakítja kisbetűsre és megvizsgálja, hogy megtalálható e benne a keresett szöveg             // a find() függvény a sztring pozícióját adja meg, ahol megtalálta, vagy -1-et ha nem találta meg            tbody.appendChild( create_row(oDSO.recordset("ev").value, oDSO.recordset("nev").value, oDSO.recordset("nemzetiseg").value) );             // a táblázathoz hozzácsatoljuk az új sort, amelyet a create_row() öggvényünk hoz létre a rekord elemek alapján    found = true; //van találat           } oDSO.recordset.moveNext(); // az elemmutatót a kövtkező elemre állítja       } if(!found)  //amennyiben nem volt találat egy üzenetet küldünk a felhasználónak     alert("Nincs találat!"); } // --> </SCRIPT> </HEAD> <BODY> <TABLE>   <TR>     <TD VALIGN="top">       <INPUT TYPE="text" ID="search_str" STYLE="width:200px;">       <INPUT TYPE="button" VALUE="Keress" ONCLICK="find_str()">     </TD>   </TR>   <TR>     <TD>       <INPUT TYPE="radio" NAME="rsearchfor" CHECKED> Név       <INPUT TYPE="radio" NAME="rsearchfor"> Év       <INPUT TYPE="radio" NAME="rsearchfor"> Nemzetiség     </TD>   </TR> </TABLE> <BR><HR><BR> <DIV STYLE="overflow-y:auto; overflow-x:hidden; width:450px; height:500px;">   <TABLE WIDTH="420">     <THEAD>       <TR>         <TD WIDTH="70"><B>Évszám</B></TD>         <TD WIDTH="200"><B>Versenyző neve</B></TD>         <TD WIDTH="150"><B>Nemzetiség</B></TD>       </TR>     </THEAD>     <TBODY ID="list_tab"> <!-- ide lesznek létrehozva a táblázat egyes sorai a találatok alapján -->     </TBODY>   </TABLE> </DIV> </BODY> </HTML>
Tabular Data Control objektum

Ahogy azt a cikk elején ígértem megismerkedünk egy kicsit közelebről a Tabular Data Controllal vagy közismertebb nevén a TDC-vel. A TDC egy Microsoft által fejlesztett adattárolási technológia, mely a felhasználó gépén ActiveX komponens formájában van jelen és az adatokat szöveges fájl formájában tárolja. Az adatok az úgynevezett elválasztókkal vannak oszlopokra bontva. Az adatbázis egyes rekordjai új sorokba kerülnek (új sor és kocsi vissza karakterekkel vannak elválatszva), amelyet nem lehet külsőleg változtatni.

Nézzük meg rögtön, hogyan is nézne ki a forma1 világbajnokait tartalmazó adatbázisunk TDC-ben:

f1vilagbajnokok.txt

ev|nev|nemzetiseg !1954!|!Juan Fangio!|!Argentin! !1955!|!Juan Fangio!|!Argentin! !1956!|!Juan Fangio!|!Argentin! !1963!|!Jim Clark!|!Brit!
Ahogy a forrás fájlból is rögtön kitűnik a fájl első sora az oszlop definíció, melyben megadjuk az adatbázis egyes oszlopainak nevét. Ezt követő sorokat maguk az adatok alkotják. Az adatok elválasztókkal (jelen esetben "|") és szöveg kvalifikátorokkal (jelen esetben "!") vannak elválasztva. A szöveg kvalifikátorok és adat elválasztók együttes használatának lényege, hogy a létező összes karaktert (még az elválasztókat is) használhassuk mint adat, tehát: |!a|b != a&b!| érvényes adata a|b != a&b.

Mivel a TDC nyújtotta lehetőségek elég szűkösek és cikkünk tárgya sem a TDC bemutatása, ezért egyetlen a maximumhoz közeli példán szeretném bemutatni a működését. A példa tartalmaz rendezést, válogatást, elem hozzáadást és elem törlést (melyeket igaz, nem lehet menteni). Nos akkor a példa forrása:

f1_vilagbajnokok_TDC.htm

<HTML> <HEAD> <TITLE>TDC DSO</TITLE> <OBJECT ID="oDSO" CLASSID="CLSID:333C7BC4-460F-11D0-BC04-0080C7055A83" onDataSetComplete="disp();">   <PARAM NAME="CharSet" VALUE="windows-1250">   <PARAM NAME="TextQualifier" VALUE="!">   <PARAM NAME="FieldDelim" VALUE="|">   <PARAM NAME="DataURL" VALUE="f1vilagbajnokok.txt">   <PARAM NAME="UseHeader" VALUE="true"> </OBJECT> </HEAD> <BODY> <input type="text" readonly id="disp" size="5"><br> <input type="button" value="<" onclick="elozo_record()"> <input type="button" value="Mutat" onClick="record_mutat()"> <input type="button" value="Töröl" onClick="record_torol()"> <input type="button" value=">" onclick="kovetkezo_record()"><br> <input type="button" value="Új hozzáadása" onclick="uj_record()"><br> <B>Rendezd <SELECT onchange="oDSO.Sort=('+'+this.value); oDSO.Reset();disp()" >   <OPTION VALUE="">Rendezetlen</OPTION>   <OPTION VALUE="nev">név</OPTION>   <OPTION VALUE="ev">év</OPTION>   <OPTION VALUE="nemzetiseg">nemzetiség</OPTION> </SELECT> szerint es mutasd a(z) <SELECT onchange="oDSO.Filter=('nemzetiseg='+this.value); oDSO.Reset();disp()" >   <OPTION VALUE="">összes</OPTION>   <OPTION VALUE="Amerika">amerikai</OPTION>   <OPTION VALUE="Ausztral">ausztrál</OPTION>   <OPTION VALUE="Argentin">argentin</OPTION>   <OPTION VALUE="Brit">brit</OPTION>   <OPTION VALUE="Finn">finn</OPTION>   <OPTION VALUE="Francia">francia</OPTION>   <OPTION VALUE="Kanada">kanada</OPTION>   <OPTION VALUE="Olasz">olasz</OPTION>   <OPTION VALUE="Nemet">német</OPTION>   <OPTION VALUE="Uj zeland">új zéland</OPTION>   <OPTION VALUE="Osztrak">osztrák</OPTION> </SELECT> nemzetiségűeket</b> <P> <TABLE DATASRC="#oDSO">   <THEAD>     <TR>       <TD width="70"><B>Évszám</B></TD>       <TD width="150"><B>Versenyző neve</B></TD>       <TD><B>Nemzetiség</B></TD>     </TR>   </THEAD>     <TR>       <TD bgcolor="silver"><SPAN DATAFLD="ev"></SPAN></TD>       <TD bgcolor="gray"><SPAN DATAFLD="nev"></SPAN></TD>       <TD bgcolor="silver"><SPAN DATAFLD="nemzetiseg"></SPAN></TD>     </TR> </TABLE> <SCRIPT TYPE="text/javascript" LANGUAGE="JavaScript"> <!-- function elozo_record() //a rekordhalmaz elemmutatóját állítja az előző elemre {  //ha a mutató az 1. elemre mutat akkor az utolsóra állítja a mutatót   if(oDSO.recordset.AbsolutePosition==1)oDSO.recordset.MoveLast();      else oDSO.recordset.MovePrevious();  //ellenkező esetben az előző elemre állítja az elemmutatót   disp(); //mivel változott az elemmutató pozíciója frissíteni kell a kijelző tartalmát } function kovetkezo_record() //a rekordhalmaz elemmutatóját állítja a következő elemre, tehát az elozo_rekord() ellenkezőjét csinálja {   if( oDSO.recordset.AbsolutePosition == oDSO.recordset.RecordCount )oDSO.recordset.MoveFirst();      else oDSO.recordset.MoveNext();   disp(); } function record_mutat() //egy JavaScriptes üzenőablakban megmutatja az aktuális rekord tartalmát {   alert("Év: "+oDSO.recordset.fields('ev')+"\nNév: "+oDSO.recordset.fields('nev')+"\nNemzetiség: "             +oDSO.recordset.fields('nemzetiseg')); } function disp() //a disp IDvel rendelkező input type="text" mező értékéhez rendeli hozzá az adatbázis aktuális {                         //hosszát és az elemmutató aktuális pozicióját   document.getElementById("disp").value = oDSO.recordset.AbsolutePosition + "/" + oDSO.recordset.RecordCount; } function uj_record() //új rekordot fűz az adatbázis végéhez {   oDSO.recordset.AddNew(); //hozzáad egy üres elemet és ráállítja az elemmutatót   oDSO.recordset.fields('ev') = window.prompt("Add meg az évet",""); //az új üres elem 'ev' nevű mezőjét teszi   // egyenlővé a felhasználó által megadott értékkel, mivel az elemmutató az új elemre lett állítva   oDSO.recordset.fields('nev') = window.prompt("Add meg a nevet",""); //ugyanaz mint feljebb   oDSO.recordset.fields('nemzetiseg') = window.prompt("Add meg a nemzetiséget","");   disp(); //mivel megváltozott az elemmutató pozíciója és az adatbázis rekordjainak száma, frissíteni kell a kijelzőt   alert("Új rekord hozzáadása sikeres!"); //felhasználó informálása a sikeres rekord felviteléről } function record_torol() //törli az aktuális (elemmutató által mutatott) rekordot {   oDSO.recordset.Delete();   disp(); //frissíti a kijelzőt, mert csökkent a rekordok száma az adatbázisban és az elemmutató az első elemre mutat   alert("Rekord törlése sikeres!"); //felhasználó informálása a sikeres törlésről } //--> </SCRIPT> </BODY> </HTML>
Amint azt már elmítettük a TDC egy ActiveX vezérlő formájában van jelen a gépünkben, amelyet az OBJECT elemmel illesztünk be a HTML oldalba. A TDC objektumnak paraméterként adjuk át az egyes feldolgozási utasításokat: szöveg kvalifikátort, elválasztót, kódólási formát és az URL-t. A TDC objektumhoz hozzárendeltünk egy onDataSetComplete eseményt, amely akkor következik be (és hívja meg a disp() metódust, mely funkciójáról később lesz szó), amikor az adatok betöltődtek.

Adatok rendezése
Ha az első SELECT megváltozik (onChange), megváltoztatja a TDC Sort tulajdonság értékét a kiválasztott elem értékére (ami egyben az egyik oszlop neve is az adatbázisban) (TDC.Sort=('+'+this.value)), amely hatására rendeződik az adatbázis a megadott módon. Biztos mindenkinek feltűnt a '+' jel az Sort tulajdonság értékében. Jelentése nem más mint a rendezés iránya ('+'-normál rendezés, '-'-fordított rendezés). Minden rendezés illetve kiválasztás után frissítenünk kell a megjelenített adatokat (TDC.Reset())

Adatok kiválasztása
Működése annyiban különbözik a rendezéstől, hogy változtatás esetén (második SELECT elem) a TDC Filter tulajdonságának értékét változtatjuk a következő képpen: adatbázis sorának értéke egyenlő egy bizonyos értékkel (mi esetünkben a SELECT-ben kiválasztott értékkel). Vagyis a mi példánkban: TDC.Filter=('nemzetiseg='+this.value) jelentése: csak azokat a sorokat irasd ki, amelynél a nemzetiség megegyezik a SELECTben kiválasztottal.

Bővebb információ a egyes metódusok működéséről a program kommentárjaiban található, valamint az egyes DSO-k részletes leírása a www.microsoft.com-on található meg Microsoft Universal Data Access címszó alatt.

Bízom benne, hogy mindenki DSO-k utáni étvágyát és érdeklődését legalább részlegesen ki tudtam elégíteni. A következő részben DOM objektum modell segítségével fogjuk végigjárni és megjeleníteni az XML dokumentumokat. Előtte viszont ajánlanám minden olvasó szíves figyelmébe a JavaScript alap szintű megértését, mivel az egész cikk ezen kliens oldali szkript nyelvre fog épülni.

A cikkben közölt forráskódok összetömörítve innen tölthetők le.