Könyvhöz tartozó online melléklet
Könyv: Webalkalmazások fejlesztése Ajax segítségével (Kris Hadlock)
Melléklet: Olvasson bele!
1. fejezet Az AJAX bemutatása
Köszönet mindenkinek, aki kezébe vette
ezt a könyvet! Ebben a kötetben a célunk nem csupán az, hogy megvizsgáljuk az Ajaxot
meghatározó technológiákat és azt, hogy ezek kölcsönhatásai miként vezetnek hatékony
ügyféloldali együttműködéshez, hanem azt is meg szeretnénk mutatni, hogyan
lehet bármilyen Ajax-megfelelő webes alkalmazásban újrahasznosítható, hasznos
kódokat írni. Ezek a kódok a vállalkozási szintű alkalmazásokban szükséges
méretezhetőség és rugalmasság érdekében teljesen objektumközpontúak lesznek.
A könyv fejezetei végigvezetnek bennünket az egyes példákon: hogyan lehet újrahasznosítható
Ajax motort készíteni, hogyan lehet az Ajaxszal együttműködő összetevőket
létrehozni, valamint – ez a szerző kedvence – miként lehet az Ajax segítségével
kiszolgálóoldali nyelvekhez kapcsolódni. Az Ajax különböző támogató technológiákat
igényel – az XML-t (Extensible Markup Language, bővíthető jelölőnyelv)
és a JSON-t (JavaScript Object Notation, JavaScript objektumjelölés) az adatcseréhez,
továbbá a JavaScriptet és a CSS-t (Cascading Style Sheets, többszintű stíluslapok)
az adatleképezéshez és -megjelenítéshez –, ezért mielőtt elmerülnénk az Ajax
sokrétű világában, ezekre a technológiákra összpontosítunk. Az ügyféloldal
és a kiszolgálóoldal együttműködését megismerve megtanuljuk, hogyan lehet
az egyes kódokat működő alkalmazásokká gyúrni – végül is ezek annyira
szorosan összekapcsolódnak, hogy az Ajaxhoz mindkettő ismeretére szükség
van. Olyan, az Ajaxra alkalmazható elterjedt programozási mintákkal is foglalkozunk
majd, amelyekkel sokkal gyorsabbá és átláthatóbbá tehetjük a fejlesztést. Ez után
elsajátítunk néhány hasznos fogást, amelyekkel biztonságossá tehetjük az Ajax-alkalmazásokat,
és közvetlen felhasználói interakciót, valamint üzenetkezelést és más ügyféloldali
szolgáltatásokat biztosíthatunk.
Az Ajax mozaikszó az Asynchronous
JavaScript and XML (aszinkron JavaScript és XML) kifejezésből ered. Az Ajax
központi eleme az XML DOM (Document Object Model, dokumentum-objektummodell) részét
képező XMLHTTPRequest
objektum. Mivel az XML DOM az Ajax rendkívül fontos része, röviden tekintsük
át, hogy lássuk, hogyan kapcsolódik a könyvben tárgyalt témákhoz.
Az XML DOM
Az XML dokumentum-objektummodell az XML
dokumentumok elérésének és módosításának szabványos módját határozza meg. A DOM
hozzáférést nyújt az XML, illetve az XHTML dokumentumok szerkezetét alkotó elemekhez,
ezáltal teljes elérést nyújt a JavaScript számára. A hozzáférést a JavaScript
DOM-kezeléssel foglalkozó belső objektumhalmaza teszi lehetővé. A könyvben
végig ezt a modellt használjuk majd, mert elengedhetetlen az XMLHTTPRequest (XHR) kérelmek
létrehozásakor a kiszolgálóoldalról érkező válaszok feldolgozásához. Ahogy
korábban említettük, az XHR az Ajax-modell veleje, ami nélkül a modell nem létezne.
Mostanában mindenkit az Ajax-mozaiknak ez a darabja izgat, ugyanis lehetővé
teszi, hogy a böngésző frissítése nélkül indítsunk HTTP-kérelmeket.
Az utóbbi időben ugyan megnőtt
az Ajax körüli felhajtás, a technológia azonban már elég régóta létezik. A Microsoft
eredetileg 1999-ben bocsátotta ki a Windows IE 5-tel együtt, egy JavaScripttel
és VBScripttel elérhető ActiveX objektumként, de ma már a Mozilla, a Firefox,
a Safari és a Netscape is támogatja egy eredeti JavaScript objektum segítségével,
amelyet az Internet Explorer (IE) 7-es kiadása szintén támogat majd. Annak ellenére,
hogy ezek a technológiák korábban is léteztek, és számos fejlesztő alkalmazta
őket, csak az utóbbi időben váltak igazán népszerűvé. Ez az újonnan
szerzett népszerűség jórészt a böngészők által nyújtott támogatásnak
köszönhető, mivel a legutóbbi változatok előtt nem sok böngésző
rendelkezett a hatékony DHTML-hez, XHTML-hez, CSS-hez és XMLHTTPRequest-ekhez szükséges támogatással. Most már igen
jó, több böngészőben, illetve több felületen működő eredményt
kaphatunk az ilyen kölcsönhatások létrehozásával. Az említett technológiák jobb
támogatásával az Ajax előtérbe került, és a webfejlesztőkre ismét izgalmas
korszak köszöntött. Néhány kisebb, független cég rendszeresen áll elő
olyan alkalmazásokkal, amelyek hatékony szolgáltatásaikkal és a felhasználói élmény
bámulatos bővítésével felveszik a versenyt a munkaasztallal.
Az előnyök mérlegelése
Az Ajax olyan nyelvek hatékony
gyűjteménye, amelyek együtt könnyen használható felületeket és ügyféloldali
párbeszédet eredményeznek. Sok fejlesztőt azonban annyira izgatottá tesz
az Ajax körüli felhajtás, hogy egyszerűen beszúrják a kódot az alkalmazásba,
anélkül, hogy előzőleg felmérnék annak előnyeit. Nem minden
webalkalmazásban van szükség az Ajaxra, de egy adott alkalmazás számos eleme
jobbá tehető az Ajax előnyeinek kiaknázásával. Ebben a könyvben olyan
felhasználási mintákat tekintünk át, amelyek a visszajelzéssel, a kiszolgálóoldali
űrlapoknak az űrlap elküldése előtti ellenőrzésével és a webalkalmazások
egyes elemeit túlzások nélkül feljavítani képes Ajax-megfelelő összetevőkkel
foglalkoznak. Az Ajax olyankor is remekül alkalmazható, amikor kiszolgálóoldali
kapcsolatot akarunk létrehozni és esetleg adatbázis-műveleteket végezni a böngésző
frissítése nélkül. Az Ajax éppen emiatt annyira hatékony, hiszen lehetővé
teszi, hogy adatcserét folytassunk a kiszolgálóval, HTTP-állapotkódokat fogadjunk,
adatbázisba mentsünk, illetve meghatározzuk, hogy mi jelenjen meg a felhasználó
számára, anélkül, hogy egyszer is frissíteni kellene az oldalt. Az asztali alkalmazásokhoz
hasonlóan ez a kérelem-válasz körforgás folyamatosan fennállhat, az Ajaxszal
együttműködő webalkalmazások azonban a Weben találhatók, tehát bárki,
aki internetkapcsolattal rendelkezik, elérheti azokat, és nem kell semmit letöltenie
vagy szállítási költséget fizetnie nagy, tarka dobozokért. Az Internet az új
munkaasztal – a szoftver nagyszabású változásának küszöbén állunk, amelyben az igény
szerint lehívható információ úttörőiként tevékeny szerepet vállalhatunk.
Az Ajax értékes kapcsolatot teremthet a
felület és a kiszolgálóoldali logika között, ami lehetővé teszi, hogy a kiszolgálóoldal
nagy teljesítményű és hatékony legyen, miközben egyszerű, könnyen
használható felülettel rendelkezik, amely igény szerinti visszacsatolást nyújt
a felhasználóknak. A kiszolgálóoldali nyelvekkel történő adatcsere, illetve
az adatbázisban tárolás lehetőségét is biztosítja, anélkül, hogy a felhasználó
és az alkalmazás közötti kapcsolat megszakadna, ahogy a hagyományos alkalmazásokban
a böngészőablak frissítésekor történik. A könyv elolvasása után minden
olyan információ rendelkezésünkre áll majd, ami a tökéletesen működő
Ajax-alkalmazások készítéséhez szükséges.
2. fejezet A kérelem
Most, hogy megismertük az Ajax hátterét,
és röviden áttekintettük, hogy mit szeretnénk elérni a példaprojektben, felkészültünk
a kérelem összeállítására. Ez a fejezet a kérelem belső működését mutatja
be, és nem csupán a kérelemobjektum létrehozásának módját ismerteti, hanem a különböző
kérelemmodellek megközelítését is megérteti.
Az XMLHttpRequest
részletesen
Az XHR (XMLHttpRequest) objektum az Ajax-motor szíve. Ez az objektum
teszi lehetővé, hogy az oldal háttérkérelemként kapjon adatokat a kiszolgálótól
(a GET eljárás segítségével), illetve
küldjön adatokat a kiszolgálónak (a POST eljárás segítségével), ami azt jelenti, hogy a folyamat
során nem frissíti a böngészőt. Ahogy azt az 1. fejezetben kifejtettük, az
Ajaxot övező felhajtást ez az objektum okozza, továbbá az, hogy az általa
létrehozott modell természetesebb, mint a szabványos HTTP- (Hypertext Transfer
Protocol, hiperszöveg-átviteli protokoll) kérelem. Ez azért van így, mert a változtatások
igény szerint történnek, amikor a felhasználó végrehajtja azokat, ezáltal a
webalkalmazás inkább asztali alkalmazás hatását kelti. Az XHR használatakor nem
kell a kiszolgálóra várni, hogy minden kérelemre új oldallal válaszoljon, és lehetővé
válik, hogy a felhasználók továbbra is kapcsolatban maradjanak az oldallal úgy,
hogy a kérelmek küldése a háttérben folyik. Ez kulcsfontosságú a közvetlen felhasználói
élmény megőrzéséhez: az a jó, ha a felhasználóknak egyáltalán nem kell tudniuk
a folyamatról, ehelyett a szolgáltatást használó aktuális feladatra összpontosíthatnak.
Az XHR igénykiszolgáló (on-demand) jellege az olyan webalkalmazásoknál rendkívül
hasznos, ahol a felhasználók feladatokat próbálnak megoldani, mert a szabványos
HTTP-kérelem inkább a bemutató típusú webhelyeknél alkalmazható.
A háttérben történő adatkezeléstől
eltekintve az XHR objektum GET
és POST eljárása ugyanúgy működik,
mint egy hagyományos HTTP-kérelemnél. A POST és a GET
eljárás alkalmazásával egyaránt adatkérelmet küldhetünk a kiszolgálónak, amelyre
valamilyen szabványos formátumban kapunk választ. A válaszok leggyakrabban XML,
JSON és szöveges formátumban érkeznek. A 3. fejezetben az összes formátumot
részletesen áttekintjük. A POST
kifejezetten 512 bájtnál nagyobb adatok küldésénél hasznos (ezt a méretet a GET eljárás nem képes kezelni).
A válasz fogadása után a DOM vagy a DHTML – amely az XHTML, a JavaScript és a
CSS keveréke – segítségével tölthetjük be a kiszolgálótól származó új adatokat
az alkalmazásba.
Minden Ajax-kérelem egy ügyféloldali
művelettel indul, amelyet általában egy JavaScript-kód kezel. A JavaScript
létrehozza az XHR objektumot, és HTTP-kérelmet küld a kiszolgálónak. Ez után
sokféle lépés következhet. Vessünk egy pillantást a három leggyakoribb kérelemmodellre
és azok folyamataira.
Szabványos XHR
Ha egy Ajax-kérelmet lebontunk a puszta
működés szintjére, csupán ez marad. Ebben az esetben az XHR objektum a GET eljárás segítségével egy
azonos tartományban található állandó XML, JSON vagy szövegfájlt kér, amelyet
azután a kiszolgáló visszaküld, hogy a kérelmet indító ügyféloldali kód kezelje.
A 2.1. ábrán a szabványos Ajax-modell folyamatát láthatjuk.
2.1.
ábra
Ez a kérelem az Ajax
kérelem-válasz modelljének legegyszerűbb formája, amely mindössze egy azonos
tarto-mányban található XML, JSON vagy szövegfájlt igényel
Ez a kérelemfajta olyankor lehet hasznos,
amikor egy webhez értő ügyfél vagy egy fejlesztő frissíti a kért
fájlt a kiszolgálón, ami ritkán fordul elő, különösen a nagyméretű alkalmazásoknál.
Ha ez a modell nem felel meg az igényeinknek, a következő megközelítésben
már szerepel az, ami ebből a modellből leginkább hiányzik: az adatbázis.
Adatbázis-megfelelő XHR
Az adatbázis-megfelelő XHR-ek létrehozásának
elsajátítása olyan, mint amikor először végzünk adatbázis-műveletet.
Az új lehetőségek egész tárházát nyitja meg előttünk, és nem is annyira
bonyolult, mint képzelnénk; az adatbázisképes Ajaxszal elérhető összetett
szolgáltatásrendszert tekintve gyerekjáték. A modell használatához először
egy kiszolgálóoldali nyelvhez kell kérelmet indítani. A kiszolgálóoldali nyelv
egyedi, meghatározott adatbázis-műveletek kezelése céljából írt eljárásokkal
kérdezi le az adatbázist a kérelemnek megfelelően. Miután a
kiszolgálóoldali nyelven írt kód megkapja az adatokat, visszaküldheti az
XHR-nek, amely eredetileg az ügyféloldali kód által kezelt XML-ként, JSON-ként
vagy szövegként kérte azokat. Ez a kérelem lehetővé teszi, hogy a felhasználók
az általuk indított kérelmeknek megfelelő, egyedi adatokat kapjanak. A
2.2. ábrát tanulmányozva jobban megérthetjük az adatbázis-megfelelő XHR folyamatát.
2.2
ábra
Az adatbázis-megfelelő
XHR a lehetőségek egész tárházát nyitja meg előttünk, és magasabb
szintre emeli Ajax-alkalmazásainkat
Ez a kérelemmodell ugyan jóval hatékonyabb,
mint a szabványos kérelem, mégis lehet, hogy ennél is pontosabb szabályozhatóságot
szeretnénk. A következő modell lehetővé teszi, hogy adatokat küldjünk
az adatbázisnak, és a kérelem alapján kapjunk vissza adatot, vagy egyszerűen
egy logikai értéket kapjunk, ha az adatbázisba történő beillesztés (INSERT) sikeres volt – és mindezt
az oldal frissítése nélkül.
Adatok küldése az adatbázis-megfelelő XHR-eknek
Ha adatokat akarunk küldeni egy adatbázisba,
először egy XHR GET
vagy POST eljárást kell küldeni egy
kiszolgálóoldali nyelvű kódnak, illetve motornak. Miután a kiszolgáló megkapja
a kérelmet, elemzi az XHR által küldött XML-t vagy egyszerű kulcs-érték
párt, majd eszerint frissíti az adatbázist. Ez a kérelemmodell felhasználói beavatkozás
nyomán frissíti az adatbázist, a böngészőoldal újratöltése nélkül. Ezzel a
módszerrel remekül visszaadható az asztali alkalmazásokban szereplő „Mentés”
gomb. A példában elektronikus levelek adatbázisba mentésére használjuk majd ezt
a modellt, így a felhasználók később lehívhatják a leveleket. A 2.3. ábrán
ennek a kérelemtípusnak a folyamatát láthatjuk, az esetleges válaszadatokkal kiegészítve,
amelyeket majd a 2. fejezetben tárgyalunk.
2.3.
ábra
Az adatbázis-megfelelő
XHR POST segítségével az XHR-t teljes adatbázis-eléréssel ötvözhetjük
A fejezetben említett kérelemmodellek
közül az adatbázis-megfelelő XHR-eknek történő adatküldés a leghatékonyabb.
Lényegében teljes adatbázis-vezérlést biztosít az XHR-en keresztül. Sok különböző
helyzet létezik, amikor érdemes az adatokat XHR-rel elküldeni a kiszolgálónak.
Hasznos lehet például, ha egy jelszó kiszolgálóra küldésével, majd annak az
adatbázis-lekérdezés előtti hitelesítésével védjük az XHR-t. Az is lehet,
hogy rekordokat szeretnénk frissíteni vagy beszúrni az adatbázisba, vagy a kérelem
alapján rekordokat akarunk kijelölni.
Az Ajaxszal folytatott kiszolgálóoldali
párbeszéd lehetővé teszi az adatbázis igény szerinti frissítését, ugyanúgy,
ahogy az asztali alkalmazások mentik a munkafolyamatot. A kérelmek kiszolgálóoldalát
annyira bőven lehet tárgyalni, hogy az V. részben egy teljes fejezetet
szentelünk neki. Mielőtt azonban elmélyednénk az összetett kódban, fontos,
hogy biztos ismeretekkel rendelkezzünk az objektumokról és azok képességeiről.
Az objektum létrehozása
Az XHR és a különböző kérelemmodellek
bővebb ismeretében már összpontosíthatunk az objektum létrehozására. A kérelemobjektum
létrehozása rendkívül egyszerű, ahhoz képest, hogy mennyire hatékony egy
projektben alkalmazva.
A kérelemobjektum létrehozásához ellenőrizni
kell, hogy a böngésző az XHR vagy az ActiveX objektumot használja. A két
objektumot elsősorban az különbözteti meg egymástól, hogy melyik böngésző
használja. Az Internet Explorer (IE) 5-ös és későbbi változatai az ActiveX
objektumot, míg a Mozilla, a Firefox, a Netscape, az Opera és a Safari az eredeti
JavaScript XHR objektumot alkalmazzák. A másik különbség az egyes objektumok
létrehozásában rejlik: az IE-nél az objektum nevét paraméterként kell átadni az
ActiveX konstruktornak, míg a többi böngészőben rendelkezésre áll az eredeti
JavaScript objektum, amelyet csupán példányosítani kell:
function
makeRequest(url)
{
if(window.XMLHttpRequest)
{
request
= new XMLHttpRequest();
}
else
if(window.ActiveXObject)
{
request
= new ActiveXObject("Msxml2.XMLHTTP");
}
sendRequest(url);
}
Ahogy azt a fenti példakód mutatja, az
objektum létrehozása tényleg nagyon egyszerű feladat. Létrehozunk egy makeRequest nevű tagfüggvényt,
amely – mint az sejthető – a kérelem indítását kezeli, valamint létrehoz
egy az XHR objektum meglétét ellenőrző feltételt, amellyel megfejti,
hogy a böngésző milyen objektumot használ. Ha ez az objektum nem áll rendelkezésre,
az ActiveXObject-et keressük. Miután
meghatároztuk a helyes objektumtípust az adott böngésző számára, példányosítjuk
a megfelelő objektumot, és létrehozzuk a kérelemobjektumot. Ezzel az objektummal
ezután el lehet érni az XHR objektum összes rendelkezésre álló tulajdonságát és
tagfüggvényét, amelyeket a 2.1. és a 2.2 táblázat sorol fel.
2.1 táblázat Az XHR
tulajdonságai és azok meghatározása
Tulajdonság Meghatározás
onreadystatechange ‑Eseménykezelő, amely a kérelemobjektum
állapotának változásakor indul el.
readyState ‑Az objektum aktuális
állapotát jelző számértékeket ad vissza. Az értékek felsorolása a 2.3. táblázatban
látható.
responseText A kiszolgálótól érkező
válasz karakterlánc-változata.
responseXML ‑A kiszolgálótól érkező
válasz DOM-megfelelő dokumentumobjektuma.
status A kiszolgálótól érkező
válasz állapotkódja.
statusText Karakterláncként visszaadott
állapotüzenet.
2.2 táblázat Az XHR
tagfüggvényei és azok meghatározása
Tagfüggvény Meghatározás
Abort() Visszavonja
az aktuális HTTP-kérelmet.
getAllResponseHeaders() Kigyűjti az összes
HTTP-fejléc értékét.
getResponseHeader("címke") ‑Kigyűjti az összes meghatározott
HTTP-fejléc értékét a választörzsből.
Open("tagfüggvény", Meghatároz egy
MSXML2.XMLHTTP vagy "URL"[,
asyncFlag egy
Microsoft.XMLHTTP kérelmet, majd beállítja [, "felhasználónév"[,
a kérelemhez tartozó tagfüggvényt,
URL-t és "jelszó"]]]) a hitelesítési információkat.
Send(content) ‑HTTP-kérelmet
küld a kiszolgálónak, majd fogadja a választ.
SetRequestHeader("címke", A címke alapján meghatározza a
HTTP-fejléc értékét."érték")
Úgy tűnhet, hogy a két táblázat
nem sok lehetőséget tartalmaz, de a későbbi fejezetekben kiderül,
hogy ezek kiszolgálóoldali kóddal, adatbázissal és dinamikus ügyféloldallal
együtt alkalmazva rendkívül hatékonyak.
Aszinkron adatátvitel
Ha valaki nem járatos az adatátvitelben,
és nem pontosan érti, hogy valójában mit jelent az aszinkron adatátvitel, nem kell aggódnia: valószínűleg nem tud
arról, hogy már tisztában van a fogalommal, és valószínűleg alkalmazta is
más programok fejlesztésekor. A programozási nyelvekben ez a műveletfajta
a leggyakoribb, és az XHR, illetve ezáltal minden vállalati Ajax-alkalmazás fontos
része. Ez a rész eloszlatja az aszinkron adatátvitelt övező titokzatosságot,
mielőtt még elmerülnénk az objektumközpontú Ajax-motor kódolásában.
Az aszinkron adatátvitel olyan kétirányú
párbeszéd, ami időeltolódással történik, lehetővé téve, hogy az adatok
a maguk idejében érkezzenek, amikor hozzáférhetők. Más szóval megtehetjük,
hogy kérelmet indítunk a kiszolgálóhoz, folytatjuk a többi adat feldolgozását,
majd fogadjuk a válaszokat, amikor a kiszolgáló elérhető. Ezáltal a
webalkalmazás rendkívül rugalmassá válik. Az Ajax-motorban az XHR
kérelem–válasz modellje alaphelyzetben aszinkron jellegű. Ez azt jelenti,
hogy a kérelem–válasz adatok nem előre meghatározottak, illetve rendszeres
időközönként továbbítódnak. Ha például HTTP-kérelmet küldünk a kiszolgálónak,
folytathatjuk a többi ügyféloldali művelet feldolgozását, miközben a háttérben
a válaszra várunk. Ez mind történhet azalatt, amíg a felhasználó más feladatokon
dolgozik, vagy más műveleteket végez, és egyáltalán nincs tudomása a háttérben
folyó adatfeldolgozásról. Vagyis hívásokat indíthatunk egy kiszolgálóoldali
nyelvű programhoz, hogy adatokat keressen az adatbázisban, és azokat XML,
JSON vagy szöveges formátumban adja vissza. Adatokat is küldhetünk a
kiszolgálóoldali nyelvnek, hogy az adatbázisban tárolja azokat, vagy egy statikus
XML, JSON, illetve szövegfájl betöltésével dinamikusan feltölthetjük a webhely
oldalait anélkül, hogy frissítenénk az oldalt, vagy megszakítanánk a felhasználói
párbeszédet az ügyféloldalon.
Ennek a kérelemnek a feldolgozásához
először két XHR-tagfüggvényt kell meghívni: az open-t és a send-et.
Az XHR objektum open tagfüggvénye
három paramétert fogad. Az első egy karakterlánc, amely azt mutatja, hogy
milyen eljárással küldjük a kérelmet. Ez az eljárásérték GET, POST
vagy PUT lehet. A második paraméter
az URL, amelyet karakterlánc formájában kérünk – ez lehet XML, JSON, szöveg,
vagy ezen formátumok bármelyikét visszaadó kiszolgálóoldali nyelv. Az utolsó paraméter
– számunkra most ez a legfontosabb – olyan logikai érték, amely aszinkron átvitelnél
alapértelmezésben true
(igaz), szinkron átvitelnél pedig false
(hamis). A send tagfüggvény
az open után következik, és valójában
ez küldi el a HTTP-kérelmet, és fogadja az általunk meghatározott formátumú választ.
Egy karakterlánc paramétert vár, ami lehet XML vagy egy POST-ként küldött egyszerű kulcs–érték pár. Lássunk
egy egyszerű példát arról, hogy miként használjuk az open és a send tagfüggvényt egy egyszerű
Ajax-kérelemben:
request.open("tagfüggvény",
"URL", true);
request.send(null);
Előfordulhat, hogy az aszinkron
adatátvitel nagyszabású rendszerekben nehézkesen kezelhetőnek bizonyul,
mégis sokkal jobban méretezhető és használható, mint a szinkron adatátvitel.
Ahhoz, hogy különböző képességekkel és tapasztalatokkal rendelkező,
összetett felhasználói kört lehessen kiszolgálni, a fejlesztőknek olyan
többrétű alkalmazásokat kell létrehozniuk, amelyek sokféle feladatot tudnak
kezelni. Az aszinkron párbeszéd egyszerre több feladat végrehajtását és hatékonyabb
munkavégzést tesz lehetővé az ilyen felhasználói körnek, megkímélve
őket attól a nyűgtől, hogy a kiszolgáló válaszaira kelljen várniuk.
A szinkron műveletek megvárják a kérelemre érkező választ, mielőtt
újabb kérelmet lehetne küldeni. Egy nagyszabású webalkalmazásban egy ilyen
művelet miatt könnyen leállhat az oldal, mialatt a kiszolgáló egyenként
dolgozza fel a sorban álló kérelmeket. Az alkalmazás végül használhatatlanná
válna, és a felhasználók valószínűleg elpártolnának tőle.
A készenléti állapot
Az XHR objektum létrehozása és a kérelem
elindítása után tudnunk kell, hogy a válasz megérkezett-e. Ilyenkor használjuk
az onreadystatechange eseménykezelőt.
Az onreadystatechange eseménykezelő
akkor indul el, amikor a kérelemobjektum állapota megváltozik, és lehetővé
teszi, hogy visszahívó eljárást indítsunk. A visszahívó eljárás elindulása után
nekünk kell kezelni a választ. A 2.1. kódszövegben bemutatott, onResponse nevű egyedi
visszahívó eljárást a 3. fejezetben tárgyaljuk, ahol az Ajax-válaszok összes
elemével foglalkozunk.
2.1. kódszöveg Kérelem
küldése
function
sendRequest(url)
{
request.onreadystatechange
= onResponse;
request.open("GET",
url, true);
request.send(null);
}
A 2.2. kódszöveg egy checkReadyState nevű egyedi
eljárás, amely ellenőrzi az XHR objektum készenléti állapotát, és az egyes
állapotokat külön ágakban kezeli, az adott állapotnak megfelelő szám szerint.
Ezt az egyedi eljárást az onResponse
tagfüggvény hívja meg, hogy meghatározza az XHR objektum készenléti állapotát,
mielőtt elvégezné a válaszobjektum feldolgozását.
2.2. kódszöveg A
readyState értékének meghatározása
function
checkReadyState(obj, id)
{
switch(obj.readyState)
{
case
0:
document.getElementById(id).innerHTML
= "Kérelem küldése...";
break;
case
1:
document.getElementById(id).innerHTML
= "Válasz betöltése...";
break;
case
2:
document.getElementById(id).innerHTML
= "Válasz betöltve...";
break;
case
3:
document.getElementById(id).innerHTML
= "Válasz kész...";
break;
case
4:
document.getElementById(id).innerHTML
= "";
return
(obj.status == 200);
break;
default:
document.getElementById(id).innerHTML
= "Váratlan hiba.";
}}
Megfigyelhetjük, hogy a fenti eljárásban
két paraméter szerepel. Az első paraméter neve obj – ez a kérelmet küldő XHR objektum, amely most a
kiszolgálótól érkező válasz readyState állapotának ellenőrzésére szolgál.
A readyState-re vonatkozó különböző
visszaadott értékeket és azok magyarázatát a 2.3. táblázatban olvashatjuk.
2.3. táblázat A
readyState-értékek jelentése és meghatározása
readyState-érték Jelentés Meghatározás
0 Nincs kezdőérték Az objektumban még nem szerepelnek adatok.
1 Töltés Az objektum tölti az adatokat.
2 Töltés kész Az objektum befejezte az adatok
töltését.
3 Interaktív ‑A felhasználó kapcsolatot
létesíthet az objektummal, annak ellenére, hogy a töltés nem fejeződött be
teljesen.
4 Kész Az objektum teljes mértékben
működésre kész.
A második, id nevű paraméter az ügyféloldali XHTML-ben található
HTML elemek azonosítója. Ezt az azonosítót a JavaScript document.getElementById tagfüggvénye keresi meg, amellyel
a DOM-ot éppen használó oldalon azonosító alapján lehet megtalálni a meghatározott
elemet. Amikor ez az elem megvan, az innerHTML tulajdonságába egy testreszabott üzenet kerül,
amelyet az adott készenléti állapothoz kapcsolva akarunk megjeleníteni. Ez kitűnő
módszer arra, hogy visszajelzést adjunk a felhasználónak a kérelmek állapotáról.
A 2.2. kódszövegben látott módon olyan szöveges üzenetet adunk meg, amely lényegében
az egyes állapotokra jellemző betöltési üzenetet jelenít meg, hivatkozási
rendszert biztosítva a felhasználó számára. Ha a readyState eléri a 4-es értéket, az azt jelenti, hogy befejeződött
a töltés, és ezután a checkReadyState
eljárás megmondja, hogy a válasz állapota egyenlő-e 200-zal. A 200-as
HTTP-állapot azt jelenti, hogy a kérelem sikeres volt, és készen áll a feldolgozásra.
Ez egyike annak a sok HTTP-állapotkódnak, amit kaphatunk, és amit az Ajax-motornak
helyesen kell kezelnie. A következő részben további állapotkódokat ismerhetünk
meg, továbbá a HTTP-állapotkódok és -fejlécek leggyakoribb felhasználási módjait
bemutató példákat találunk.
HTTP-állapotkódok és
-fejlécek
Az Ajax-objektum kérelemállapota megegyezik
a kért fájl HTTP-állapotával. A HTTP-állapotkódok a kiszolgáló válaszát jelölik,
ami a kért fájl állapotát tükrözi. A HTTP-kérelem és az XHR számára elérhető
állapotkódok öt csoportba sorolhatók:
• Tájékoztató: 1xx • Ügyfélhiba: 4xx
• Sikeres: 2xx •
Kiszolgálóhiba: 5xx
• Átirányítás: 3xx
A Weben keresztül kapott állapotkódokat
számok jelölik – gondoljunk arra, amikor meg szeretnénk látogatni egy
webhelyet, és 404-es hibát kapunk. Ez nem tetszőleges szám, hanem a fájlállapot
megfelelője, ami ebben az esetben „A fájl nem található” válasz. A kiszolgálónak
– és ezáltal a kérelmet indító Ajax-motornak is – minden állapotkódot megfelelően
kell kezelnie. Az XHR objektummal történő kérelemindításkor a választ
fogadó parancsfájlnak kell feldolgoznia ezeket az állapotkódokat. Ez azt jelenti,
hogy a fejlesztő felelős azért, hogy a válasz alapján visszajelzést
adjon a felhasználónak, amit valóban meg kell tennie, ha jól használható
webalkalmazást akar készíteni. Sikeres válasz esetén az új adat jellemzően
XHTML-ként képeződik le az ügyféloldalon; ellenkező esetben megjeleníthető
valamilyen üzenet, amely értesíti a felhasználót, hogy a művelet sikertelen
volt, illetve megadja a hiba jellegét. A hibakezelés kódolása nem a legizgalmasabb
dolog a világon, de elengedhetetlen ahhoz, hogy használható alkalmazásokat készítsünk,
ráadásul olyan gyakorlatra tehetünk szert, amit más kódolási körülmények között
nem tudnánk megszerezni. A hibakezeléssel a II. részben ismerkedünk meg részletesebben,
ahol egyedi objektumokat hozunk létre az összes lehetséges állapotkód kezelésére,
valamint hasznos üzeneteket adunk válaszként a hibakereséshez, valamint a felhasználók
tájékoztatása céljából. Ha valaki többet akar megtudni a HTTP-állapotkódokról,
a W3C (World Wide Web Consortium) webhelyén, a http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html címen
megtalálja a meghatározások teljes listáját.
Az XHR objektum HTTP-fejléceket is fogadhat,
illetve beállíthat a kiszolgálón. A fejlécek segítségével meghatározott adatokat
gyűjthetünk egy kért fájlról, vagy információkat kaphatunk bizonyos
kiszolgálótulajdonságokról. Ezek az adatok például akkor lehetnek hasznosak,
amikor a tartalom típusát meghatározó content-type fejléc alapján döntjük el, hogy miként elemezzünk
egy kért fájlt. Ha a tartalom típusa mondjuk text/XML (szöveg/XML), akkor tudjuk, hogy az XML DOM alkalmazásával
elemezhetjük, és megfelelő tagfüggvényeket készíthetünk a különböző
tartalomtípusok kezelésére. Sok más döntést is lehet hozni a HTTP-fejlécek alapján.
Az XHR objektumban három eredeti fejlécfüggvény
található: a setRequestHeader,
a getResponseHeader és a getAllResponseHeaders. A setRequestHeader tagfüggvény
lehetővé teszi, hogy a fejléc címkével történő azonosításával és valamilyen
érték átadásával beállítsuk a fejléc értékét. A függvény utasításformája a következő:
request.setRequestHeader("címke",
"érték");
A kérelem fejlécének beállításával az
adott kérelem során hozzáadjuk, töröljük, felülírjuk vagy lecseréljük a
HTTP-kérelem fejlécének alapértelmezett értékét. A nyelvtanilag helytelen fejlécek
nem továbbítódnak, hanem hiba keletkezik, ezért a fejléc beállítása sikertelen
lesz.
A fejlécek beállításán túl az XHR azt
is lehetővé teszi, hogy a válasz közben lekérjük a fejléceket. Erre a célra
két tagfüggvény használható: a getResponseHeader
és a getAllResponseHeaders. A getResponseHeader tagfüggvény
a fejléc címkéjét alkalmazza paraméterként, amelynek segítségével meghatározott
adatokat szerzünk az adott fejlécből. Íme a két tagfüggvény egy-egy példája:
request.getResponseHeader("címke");
request.getAllResponseHeaders();
A getAllResponseHeaders tagfüggvény a válasz összes fejlécét
visszaadja, amelyek a választ küldő kiszolgálótól függően változnak.
A 2.4. ábrán szereplő példában egy XML fájl összes fejléce látható, amelyek
azon a Windowst futtató kiszolgálón érhetők el, ahol a szerző
webhelye jelenleg működik.
2.4.
ábra
A
getAllResponseHeaders tagfüggvénnyel lekérhető összes HTTP-fejléc
A fentiek csupán rövid bepillantást adtak
abba, hogy milyen hasznosak lehetnek a fejlécek a webalkalmazásokban. Később
több száz felhasználási módot találunk majd, de ezek nem tartoznak a könyv témájához.
A HTTP-fejlécekről a W3C webhelyén, a http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html címen
tájékozódhatunk bővebben, ahol a teljes felsorolásuk megtalálható.
3. fejezet A válasz
A 2. fejezetben a készenléti állapot és
az állapotkódok tárgyalásakor szó esett a válaszról. Ebben a fejezetben a
kérelem állapotánál tovább megyünk, és két olyan adatcsere-formátumra
összpontosítunk, amelyekben a válaszokat fogadhatjuk. Az Ajax-válaszok különböző
formátumokban érkezhetnek: a leggyakoribb a JSON, a legszélesebb körben
elfogadott pedig az XML. Mindkettő hasznos lehet, attól függően, hogy
milyen eredményt akarunk elérni. A jövőbeni kezelés szempontjából azonban
érdemes az alkalmazáson belül egyetlen formátumnál maradni, különösen akkor, ha
nagy léptékű alkalmazást készítünk. Ha például valamilyen helyzetben az
XML-t használjuk válaszformátumként, sokkal egyszerűbb, ha továbbra is
erre a formátumra számíthatunk az összes többi kérelem indításakor. Ez
alkalmazásonként változhat, de amennyiben lehetséges, kövessük ezt az elvet. A
választott megoldás méretezhetőségét is érdemes szem előtt tartani,
különösen ha olyan bővíthető alkalmazás létrehozását tervezzük,
amelyben exponenciális növekedésre számítunk. Kezdetnek tanulmányozzuk az
XML-t, annak nyelvtanát, az elemzés módját, illetve hogy miként használjuk majd
a következő alkalmazásunkban.
XML
Az XML-t (Extensible Markup Language,
bővíthető jelölőnyelv) szívesen választják XHR-ként,
egyszerűen azért, mert olyan szabványos közvetítő nyelv, amelyet
minden programozási nyelv képes használni. Ezen kívül a kiszolgáló- és az
ügyféloldalon egyaránt támogatott, emiatt egyben a legrugalmasabb megoldás is.
Az XML lényegében egy olyan egyedi címke alapú szerkezet, amelyet a
fejlesztő határoz meg. Az XML címkéi hasonlítanak a HTML címkéihez, azzal
az eltéréssel, hogy a HTML előre meghatározott címkékkel ábrázolja a
szerkezetet, például fejléc, törzs, táblázatok, és így tovább. Lássuk a HTML
táblázatok egy rendkívül egyszerű példáját, amelyet könnyen lehetne
XHTML-lé alakítani, illetve XHTML-ként alkalmazni:
<table><tr><td></td></tr></table>
Az XML ügyféloldal és kiszolgálóoldal
között történő átadásával a különböző nyelvek egyszerűen
kommunikálhatnak egymással. Rendkívül előnyös, hogy a kiszolgáló- és az
ügyféloldal között létezik ilyen közös nyelv. Lehetővé teszi, hogy
közvetlen kapcsolatot létesítsünk a grafikus felhasználói felület és egy
kiszolgálóoldali nyelv, majd kívánság szerint egy adatbázis között. A grafikus felület
és az ügyféloldal közötti XML-lel megvalósított párbeszéd lehetővé teszi a
két alkalmazásréteg teljes különválását. A grafikus felület és a
kiszolgálóoldali logika elkülönítése rendkívül fontos, mert ezáltal teljesen
önálló alkalmazást kapunk, amelyben a grafikus felhasználói felület
fejlesztői dolgozhatnak az ügyféloldalon, míg a kiszolgálóoldali
fejlesztők dolgozhatnak a kiszolgálóoldalon. Ez magától
értetődőnek tűnhet, de sok vállalatnál hiányzik ez a szemlélet,
amely az alkalmazás bizonyos részeit különválasztja a könnyebb
kezelhetőség érdekében, és lehetővé teszi, hogy a csoportok, illetve
az egyes fejlesztők a jobbításra szoruló rétegre összpontosítsanak. Ez a
megközelítés nem csupán a fejlesztőcsapatoknak rendkívül előnyös,
hanem minden olyan önálló fejlesztőnek fontos, aki az alkalmazás összes
elemén dolgozik. Ezzel a szerkezettel az egyes fejlesztők az alkalmazás
bizonyos rétegeire összpontosíthatnak, anélkül, hogy érintenék a szomszédos
rétegeket vagy módosítaniuk kellene azokat.
Az XML formázása egyszerű, de a
megoldások tervezésekor figyelembe kell venni néhány fontos alapelvet.
Képzeljük el, hogy az e-mailek adatait olyan szerkezetté kell formálni, amely
egy Ajax motoron keresztül lekérhető, és ügyféloldali JavaScript objektumokkal
megjeleníthető. A könyvben szereplő példához éppen ilyen szerkezetet
készítünk majd, amelynek tervezésekor érdemes szem előtt tartani, hogy az
alkalmazásban esetleg több objektumban, illetve helyen használjuk majd, ezért a
lehető legmagasabb elvonatkoztatási szintre van szükség. Először a
szerkezetet alkotó fő elemeket határozzuk meg.
Elemek
Az XML elemeknek nevezett egyedi címkékből áll, amelyek meghatározása
a webalkalmazások tervezési szakaszában történik. Az alkalmazásban használt
bármilyen nevet, értéket vagy adattípust jelölhetnek. Az XML-szerkezetek
létrehozásakor mi magunk vagyunk az alkalmazás tervezői, mi döntjük el,
hogy milyen adatokra van szükségünk bizonyos egységek képernyőn való
megjelenítéséhez, vagy hogy egy adott felhasználói művelet milyen választ
eredményezzen.
Fontos, hogy a szerkezetek
elvonatkoztatási szintje a lehető legmagasabb maradjon, azáltal, hogy az
elemeket nem a célalkalmazástól függően nevezzük el, de erre gyakran nincs
lehetőség. Ilyen esetekben nem szerencsés, ha külön időt szánunk
arra, hogy az XML-szerkezet elvont legyen, mert lehet, hogy nincs is szükség az
XML-adatok újrahasznosítására az alkalmazás különböző részein.
Mindamellett az e-mailes XML-mintapéldában lehetséges az elvonatkoztatás, és az
alkalmazás más területein végzünk is újrahasznosítást.
Az alábbi XML-formátum használható, de
nem kifejezetten bővíthető, illetve újrahasznosítható megoldás:
<categories>
<From/>
<Subject/>
<Date/>
</categories>
Ahhoz, hogy az alábbi kategóriák
elvontak maradjanak, az elemek nevét category-ra változtatjuk:
3.1. kódszöveg
Elvont kategórialista (.xml)
<categories>
<category>From</category>
<category>Subject</category>
<category>Date</category>
</categories>
Ez a lehetőség olyan rugalmasságot
biztosít, ami megkönnyíti a további kategóriák hozzáadását. Az utóbbi megoldás
számos okból méretezhetőbb; az egyik fontos, megjegyzendő szempont
az, hogy az XML-adatok szerkezetének megváltoztatása nélkül adhatunk a listához
új kategóriákat. Ezért olyan rugalmas és jobban bővíthető ez a
megoldás, mint az előző példáé. Ezen felül, ha objektumokat hozunk
létre az adatok megjelenítéséhez, az új elemek kezeléséhez nem kell további
elemző és megjelenítő kódot írni. Ezért fontos, hogy olyan elvont
szerkezetekkel építsük fel a megoldást, amelyek méretezhetők és könnyen
átültethetők más alkalmazásokba vagy objektumokba. Képzeljük el például,
hogy kétféleképpen kell megjeleníteni ugyanazt a kategórialistát, mondjuk
adatrácsban és e-mail előnézetben. Mindkét objektumnál használhatjuk ugyanazt
az elemhalmazt, ami kiküszöböli az alkalmazás kódjában fellelhető
ismétlődéseket.
Igaz, hogy az XML-t elemek alkotják,
mégsem lehet bármit megvalósítani kizárólag elemek alkalmazásával. Tekintsünk
át a jellemzőket, és hogy a segítségükkel miként lehet további
információkat fűzni az XML-adatokhoz.
Jellemzők
Az XML-jellemzők olyan
kiegészítő tulajdonságok, amelyeket az elemekhez adva további, a
szerkezetre vonatkozó információkat adhatunk meg. Vegyük az e-mailes példa egy
e-mail elemét. Az elektronikus levelek számos jellemzővel rendelkeznek,
például azzal, hogy milyen eseményt vált ki a levél kijelölése, vagy egy
ikonnal, ami mondjuk egy zárt vagy nyitott boríték, attól függően, hogy a
levelet elolvasták-e. Ahhoz, hogy XML-ben jelenítsük meg az elektronikus
leveleket, olyan elemcsoportot hozunk létre, amelyből később
objektum- vagy tömbgyűjtemény hozható létre az ügyféloldalon történő
elemzéskor. Az esemény és az ikon jellemzők hozzáadására itt kerül sor. A
jellemzőket egyszerűen lehet az elemekhez adni. Vessünk egy
pillantást a 3.2. kódszövegre, hogy megértsük, hogyan adjuk majd az esemény- és
az ikonjellemzőket az XML-elemhez:
3.2. kódszöveg
Elemek elvont listája (email.xml)
<items
action="alert(’Grace Hopper’);" icon="img/mail.gif">
<item><![CDATA[Grace
Hopper]]></item>
<item><![CDATA[<b>BUG
Found</b>]]></item>
<item>2006-03-31
09:27:26</item>
</items>
Van néhány probléma, amelyekkel nagyon
fontos tisztában lennünk a jellemzők használatakor, különösen a nagy
alkalmazásoknál, ahol egy tervezéskor vétett hiba nagy károkat okozhat a
bővítéskor. A jellemzők egyik legnagyobb problémája, hogy egyetlen
jellemzőbe nem lehet több értéket illeszteni. Ez olyankor okozhat gondot,
ha később úgy döntünk, hogy egy korábban jellemzőként meghatározott
elemből több példányra van szükség. Ilyenkor minden olyan helyen
módosításokat kell végeznünk (saját magunknak vagy a fejlesztőtársaknak),
ahol a jellemzőkre hivatkozunk.
Egy másik fontos probléma – amelyre a
következő részben megoldást találunk – a HTML hozzáadása az XML-hez. A
jellemzőkhöz nem adhatunk HTML-t, mert ez érvénytelen szerkezetet
eredményezne. XML-szerkezetekhez csak az elemeken belül adhatunk HTML-t. Sokkal
biztonságosabb elemet hozzáadni, mint jellemzőt, mert ha később
észreveszünk egy hibát, ahol nem a HTML-nek megfelelően formáztuk az
elemet, utólag bármikor újraformázhatjuk úgy, hogy HTML-t fogadjon, és ez nem
ütközik semmilyen kóddal, ami esetleg az elemre hivatkozik. Ha az elemzést
végző programozási nyelv által olvashatóan és az XML érvényességét
betartva szeretnénk HTML-t adni az elemekhez, CDATA címkéket kell illeszteni az
elemcímkékhez.
CDATA
A CDATA hihetetlenül hatékonnyá teszi
az XML-t – és ezáltal az azt használó webalkalmazásokat –, mivel lehetővé
teszi, hogy HTML-t adjunk az elemekhez. A HTML segítségével ezután formázott
adatokat jeleníthetünk meg, közvetlenül az Ajax-alkalmazás ügyféloldalán
szereplő DOM-elemekben. Amikor az általunk használt programozási nyelv
elemzi az XML-t, az elemcímkék közötti értékeket is elemzi. A következő példában
egy <items> elembe ágyazott <item> elemcsoportot
láthatunk:
<items
action="alert(’Grace Hopper’);" icon="img/mail.gif">
<item>Grace Hopper</item>
<item>BUG Found</item>
<item>2006-03-31
09:27:26</item>
</items>
Az egymásba ágyazott elemeket az
elemzőnek részelemekre kell bontania ahhoz, hogy a programozási nyelv
mondjuk gyermekcsomópontokként értelmezze azokat. Ez azt jelenti, hogy nem
lehet HTML-címkéket ágyazni az XML-elemekbe, mert az elemző nem
HTML-címkékként, hanem a szülőelem beágyazott vagy gyermekelemeiként
értelmezi ezeket – ezáltal az XML érvénytelenné válik, ami elemzési hibát vagy
nem várt eredményt idéz elő. Az alábbi XML-t látva az elemző a HTML
„félkövér” címkéjét (</b>)
XML-elemként értelmezi, mert nem HTML-címkékként, hanem beágyazott
XML-címkékként látja a félkövér címkéket:
<item><b>BUG
Found</b></item>
Ahhoz, hogy HTML-t adjunk az
XML-elemhez, CDATA-t kell használnunk. Az XML-elemzők nem elemzik az olyan
adatokat, amelyek közvetlenül ezeket a címkéket követik, így érvényes marad az
XML-szerkezet és egyúttal az oldalon megjeleníteni kívánt HTML is. Az alábbi
kódban érvényes XML-t láthatunk, a CDATA segítségével beágyazott
HTML-címkékkel:
<item>
<![CDATA[<b>BUG Found</b>]]></item>
Amikor az ügyféloldali parancsnyelv –
esetünkben a JavaScript – elemzi ezeket az adatokat, a HTML úgy képeződik
le, ahogy a címkék között szerepel. A BUG Found
szövegérték például félkövéren jelenik meg a grafikus felületen, ha az adatot
beillesztjük a dokumentumba. Ezt úgy tehetjük meg, hogy a DOM segítségével
egyszerűen kijelölünk egy HTML-címkét, majd az értéket összekapcsoljuk a
JavaScript belső innerHTML
tulajdonságával, vagy a document.write();
alkalmazásával közvetlenül arra a helyre írjuk az értéket, ahová a kódsort
helyezzük. Most pedig mélyedjünk el jobban a válasz elemzésében!
Az XML elemzése
Amikor az XML-ben használt formázást és
címkeneveket tervezzük, több dolgot is fontos szem előtt tartani.
Általában hasznos például, ha egyedi neveket adunk a fájlban különböző
szinteken elhelyezkedő elemeknek. Így elkerülhetjük a JavaScript belső
getElementsByTagName
tagfüggvényének használatakor adódó elemzési problémákat. Ez a függvény az
összes általunk meghatározott nevű elem tömbjét adja vissza, és nem
figyeli, hogy ezek milyen szinten helyezkednek el. Az egyik hiba, ami
ebből származhat, az, hogy a különböző szinteken található, nem
összetartozó értékcsoportok egyetlen tömbbe kerülnek, amely nem ábrázolja az
adatok megfelelő helyét, és ez elemzéskor rémálommá válik számunkra,
illetve a fejlesztőtársak számára. Léteznek módszerek az ismétlődő
nevekkel rendelkező beágyazott címkéket használó adatok elemzésére,
például a childNodes
tulajdonsággal történő kijelölés, de ez nehézkes, és hosszabbá teheti a
fejlesztési folyamatot. Azt is megtehetjük, hogy olyan objektumot hozunk létre,
amely meghatározott elemeket meghatározott szinteken, nevek szerint elemző
tagfüggvényekkel rendelkezik, ahogy más nyelvekben az XPATH, vagy
jellemzők segítségével különböztetjük meg az azonos névvel rendelkező
eltérő csomópontokat. A mi céljainkhoz azonban elég, ha egyszerűen
úgy határozzuk meg a szerkezetet, hogy ne kelljen a fenti nehézségek miatt
aggódni.
Az XML különböző nyelvű
kódokkal való elemzéséhez léteznek teljesen szabványos módszerek, az XML
JavaScripttel való elemzése azonban kicsit más. Mint azt korábban említettük, a
JavaScriptben létezik egy getElementsByTagName
nevű belső tagfüggvény, amely közvetlenül név szerint képes kijelölni
egy elemcsoportot, és lehetővé teszi a hozzáférést az elem-, illetve
jellemzőértékek egyszerű elemzése érdekében. Ez a függvény egyetlen
elemet vagy elemcsoportot ad vissza a paraméter által meghatározott címkenév
alapján, ahogy az alábbi példában:
response.getElementsByTagName(’items’);
Amikor a függvény egy elemcsoportot
talál, a gyermekcsomópontok tömbjét adja vissza, amelyet elemezni kell ahhoz,
hogy megkapjuk a belső csomópontértékeket. Ha ezt az eljárást akarjuk
alkalmazni az elemzésben, ügyelni kell, hogy helyesen jelöljük ki az XHR
objektumot a válasz elkészülte után. A 3.3. kódszövegre pillantva azt a kész
XML-mintát látjuk, amelyet majd elemzési példaként használunk:
3.3. kódszöveg Az
e-mail XML fájljának végső változata (email.xml)
<?xml
version="1.0" encoding="iso-8859-1"?>
<data>
<categories>
<category>From</category>
<category>Subject</category>
<category>Date</category>
</categories>
<row>
<items action="alert(’Grace
Hopper’);" icon="img/mail.gif">
<item><![CDATA[Grace
Hopper]]></item>
<item><![CDATA[<b>BUG Found</b>]]></item>
<item>2006-03-31
09:27:26</item>
</items>
</row>
<row>
<items action="alert(’Pi
Sheng’);" icon="img/mail.gif">
<item><![CDATA[Pi
Sheng]]></item>
<item><![CDATA[Movable
type]]></item>
<item>2006-01-15
12:32:45</item>
</items>
</row>
</data>
Az elemzőfüggvények kipróbálásához
olyan HTML fájlt kell létrehozni, amelyben két hiperhivatkozás található: az
egyik egy XML fájlt kér válaszként, a másik pedig egy JSON fájlt. A 3.4.
kódszöveg azt a HTML indexfájlt tartalmazza, amely a kérelmet indító
hiperhivatkozásokat tartalmazza:
3.4. kódszöveg Az
XML és a JSON kérelemminta indexfájlja (index.html)
<html>
<head>
<title>The
Response</title>
<script
type="text/javascript"
src="javascript/ajax.js"></script>
</head>
<body>
<a
href="javascript:makeRequest(’services/email.xml’, å onXMLResponse);">xml</a>
|
<a
href="javascript:makeRequest(’services/email.js’,
å onJSONResponse);">json</a>
<br/><hr
noshade="noshade">
<div
id="loading"></div>
<div
id="body"></div>
</body>
</html>
Láthatjuk, hogy ebben az állományban mindössze
két hiperhivatkozás található, amelyekre kattintva kérelmet indítunk a 2.
fejezetben létrehozott makeRequest
tagfüggvény segítségével. Az egyetlen különbség az, hogy most van egy változó
visszahívó függvényünk is, ami lehetővé teszi, hogy tetszés szerinti
visszahívó függvényt adjunk át, hogy kedvünk szerint, egy bizonyos kérelem
alapján végezzük az elemzést. Két div
címke is rendelkezésre áll a különböző adatok megjelenítésére: az egyik
címke id (azonosító) értéke loading (töltés), a másiké body (törzs). A loading div a készenléti állapot ellenőrzésekor visszaadott
betöltési üzenethez szükséges, a body
div pedig a válasz elemzése
utáni tényleges adatmegjelenítésre szolgál. Az adatok tetszőlegesen
formázhatók: az egyszerű adatlistától kezdve egy műveleti adatokat
tartalmazó, XHTML-lel formázott GUI-ig bármilyen formában megjeleníthetők.
Az XML-válasz formázása előtt meg kell adni a kérelemben meghatározott
visszahívó függvényt. Példánkban egy onXMLResponse nevű függvényt adunk az indexbe
betöltött ajax.js-hez,
ellenőrizzük a készenléti állapotot, majd az XHR responseXML tulajdonságával jelöljük ki az XML-adatokat
(lásd a 3.5. kódszöveget).
3.5. kódszöveg
Válaszfüggvény létrehozása és a készenléti állapot ellenőrzése
(ajax.js)
function
onXMLResponse()
{
if(checkReadyState(request,
’loading’) == true)
{
var response =
request.responseXML.documentElement;
//Itt történik az
elemzés
}
}
A készenléti állapot
ellenőrzésével két dolgot teljesítünk: először ellenőrizzük a
kérelem állapotát, hogy kiderítsük, befejeződött-e a töltés, illetve
készen áll-e az elemzésre, másodszor pedig átadjuk a div azonosítót a készenléti állapot üzeneteinek az innerHTML tulajdonsággal
történő megjelenítéséhez. A 2.1. táblázatban felsorolt tulajdonságok közül
kettőt használhatunk az adatok XHR-rel történő kijelöléséhez: az
egyik a responseText,
a másik a responseXML. A responseText
tulajdonság a kiszolgálóról kapott válasz karakterlánc-változatát, a responseXML tulajdonság pedig
a kiszolgáló válaszának DOM-megfelelő dokumentumobjektumát adja vissza.
Ebben az esetben a responseXML
tulajdonságot alkalmazzuk, mivel DOM-megfelelő objektumra van szükségünk
az XML-válaszhoz, hogy megkezdhessük az elemek értékeinek elemzését.
Először az XML fájl kategóriaértékeit elemezzük, majd az innerHTML tulajdonságon
keresztül átadjuk ezeket a body
div-nek, a 3.6. kódszövegben
látható módon.
3.6. kódszöveg
Kategóriaértékek kigyűjtése az XML-ből (ajax.js)
//Kategóriák
document.getElementById("body").innerHTML
= "------------<br/>";
document.getElementById("body").innerHTML
+= "<b>Categories</b><br/>";
document.getElementById("body").innerHTML
+= "------------<br/>";
var categories =
response.getElementsByTagName(’category’);
for(var i=0;
i<categories.length; i++)
{
document.getElementById("body").innerHTML +=
å response.getElementsByTagName( å ’category’)[i].firstChild.data
+"</br>";
}
Az egyes kategóriák kijelöléséhez a getElementsByTagName
tagfüggvényt kell alkalmaznunk, és a category értéket kell átadni paraméterként. Így egy
kategóriatömböt kapunk eredményül, amelynek elemeit egyenként a body div-hez adhatjuk. A kategóriák hozzáadásakor az összes
címkékben szereplő adatot kijelöljük, hogy minden elem tényleges értékét
megjelenítsük.
A kategóriák megjelenítése után
továbbléphetünk az XML item
(elem) címkéire. Ezeket kissé eltérően elemezzük, a szülők, vagyis a row (sor) címkék
kijelölésével, amivel egy sorokból álló tömböt kapunk. Ezután a sorokat bejárva
a JavaScript belső getAttribute
tagfüggvényének segítségével az items
címkékben szereplő action
(művelet) és icon
(ikon) jellemzőket jelöljük ki. Miután befejeztük a jellemzőértékek div-be írását, önálló elemeket
jelölhetünk ki az egyes sorokban. Ezt úgy hajtjuk végre, hogy két for ciklust ágyazunk a
soroknál használt for
ciklusba, ezáltal egy háromrétegű ciklust kapunk. Az egyik ciklus az items címke, a másik pedig az
egyes item címkéken belül
szereplő csomópontértékek bejárására szolgál, a 3.7. kódszövegben látható
módon.
3.7. kódszöveg
Elemértékek kigyűjtése az XML-ből (ajax.js)
//Elemek
document.getElementById("body").innerHTML
+= "------------<br/>";
document.getElementById("body").innerHTML
+= "<b>Items</b><br/>";
document.getElementById("body").innerHTML
+= "------------<br/>";
var row =
response.getElementsByTagName(’row’);
for(var i=0;
i<row.length; i++)
{
var action = å
response.getElementsByTagName(’items’)[i].getAttribute(’action’);
var icon = å
response.getElementsByTagName(’items’)[i].getAttribute(’icon’);
document.getElementById("body").innerHTML += å action +"<br/>"+ icon
+"</br>";
var items =
response.getElementsByTagName(’items’)[i].childNodes;
for(var j=0; j<items.length; j++)
{
for(var k=0;
k<items[j].childNodes.length; k++)
{
document.getElementById("body").innerHTML +=
å items[j].childNodes[k].nodeValue
+"</br>";
}
}
document.getElementById("body").innerHTML +=
"------------<br/>";
}
A kért XML elemzése meglehetősen
egyszerű, ha tudjuk, hogy a kiszolgáló válasza milyen formátumban várható.
Ha az előző példaválaszban nem tudtuk volna, mire számítsunk,
kezdetnek a responseText
tulajdonság alkalmazásával karakterláncként megjeleníthettük volna a
szerkezetet, hogy megfejtsük, milyen címkéket kell kijelölni:
function
onXMLResponse()
{
if(checkReadyState(request, ’loading’) ==
true)
{
var response = request.responseText;
alert(response);
}
}
Így a teljes XML-szerkezetet egy
figyelmeztető üzenetben kaptuk volna meg. Ezután már meg lehet nézni a
szerkezetet, és el lehet dönteni, hogy mit akarunk elemezni a responseXML tulajdonság
segítségével.
Láthatjuk, hogy az XML gyakorlatilag
bármilyen adatszerkezetet képes megvalósítani, és valójában az XML-t olvasó
objektumokon múlik, hogy valami hasznosat kezdjenek vele. Vizsgáljuk meg, hogy
ehhez képest milyen a JSON, és hogy milyen előnyöket nyújt a válaszok
formázásakor.
JSON
A JSON, azaz JavaScript Object Notation (JavaScript objektumjelölés) adatcsere-formátum
egyre szélesebb körben elfogadott, mint az Ajax-alkalmazások egy lehetséges
formátuma. Lényegében egy társításos tömb vagy hasítótábla, attól függően,
hogy melyik programnyelvben mozgunk a legotthonosabban. Ez azt jelenti, hogy a
nevek, illetve címkék értékekhez rendelődnek egy tömbszerkezetben vagy
vesszőkkel tagolt listában. Az egyszerű nyelvtannak és a JavaScript
szabványos ügyféloldali parancsnyelvként történő átvételének
köszönhetően ez a formátum az Ajax-alkalmazásokban használt adatformátumok
között felveszi a versenyt az XML-lel. Ezen kívül a JSON-elemzést támogatja a
JavaScript eval
tagfüggvénye, ami rendkívüli módon megkönnyíti az elemzést, ha az
Ajax-alkalmazásunkban használjuk. Vannak azonban buktatói is: az eval alkalmazása miatt nagyon
lelassulhat az elemzés, és ami még fontosabb, az eval a biztonság szempontjából nagyon veszélyes lehet. Ez
szerencsére nem jelenti azt, hogy a JSON kiesik az Ajax adatcsere-formátumainak
versenyéből, csupán az a lényeg, hogy körültekintőbbnek kell lennünk,
amikor ezt választjuk adatformátumként. Többek között úgy lehetünk
elővigyázatosak, ha titkosított jelszavakat adunk a kérelmekhez, ahogy azt
a 23. fejezetben majd láthatjuk.
Most, hogy már rendelkezünk némi
ismerettel a JSON-ról, lássuk, hogy milyen nyelvtant kell követnünk a
szerkesztésekor.
A JSON nyelvtana
A JSON nyelvtana rendkívül
egyszerű, és igazolhatóan könnyebben kezelhető, mint az XML-é. Az XML
az elemek ismétlődése miatt meglehetősen nehézkes sok adat
kezelésénél, ezért ilyenkor a JSON remek választás lehet. A JSON nem szabványos
adatcsere-formátum, de a sok rendelkezésre álló elemző miatt járható utat
jelent. A http://www.json.org
címen szinte az összes JSON-elemző fellelhető, de ha nem találunk az
adott nyelvhez tartozó elemzőt, könnyen írhatunk egyet, hiszen a nyelvtan
elemzése nem túl nehéz.
A JSON nyelvtana objektumközpontú
szemlélettel vizsgálva könnyen befogadható. A JSON fájlok szerkezete megfelel a
JavaScript-objektumokénak, abból a szempontból, hogy egy fájl több objektumból,
tömbből, karakterláncból, számból és logikai értékből állhat. A 3.1.
táblázat JSON-ként formázott adattípusokat sorol fel.
3.1. táblázat Az
egyes adattípusok JSON-megfelelői
Adattípus JSON ábrázolás
Karakterlánc "icon":
"img/mail.gif"
Szám "mynumber": 100
Logikai érték "myboolean":
true
Tömb "items": [ { "action": "alert(’Grace
Hopper’);", "icon":
"img/mail.gif", "item": ["Grace
Hopper", "<b>BUG Found</b>", å "2006-03-31
09:27:26"] },
{ "action": "alert(’Pi
Sheng’);", "icon": "img/mail.gif",
"item": ["Pi Sheng", "Movable type", å "2006-01-15
12:32:45"] } ]
Objektum "categories": { "category": ["From", "Subject",
"Date"] }
Az egyes JSON-adattípusokat egy név
vagy egy címke jelöli, amely után kettőspont áll. Csak az értékek
változnak típusonként. Az egyszerűbb típusok egyértelműek: a
karakterlánc értékeket karakterláncok jelölik, a számokat számok, a logikai
értékeket pedig a true
(igaz) vagy a false
(érték). A tömbök és az objektumok bonyolultabb adattípusok. A tömböket
szögletes zárójelek között álló, vesszőkkel tagolt lista képviseli. A
JSON-objektumok bármilyen adattípus tulajdonságait tartalmazhatják – ezek
kapcsos zárójelek között állnak, úgy, ahogy más nyelvekben az osztályokat
formázzák. Annyi a különbség, hogy itt nem adunk nevet a fő szerkezetnek.
A JSON használata
A JSON nyelvtanának megértése után a
formázás meglehetősen egyszerű. Ha nagy menynyiségű adattal
dolgozunk, érdekes összehasonlítani a JSON és az XML formátumot, mert a JSON
végül kisebb adatszerkezetet eredményez. Ebben a részben átalakítjuk az XML
rész példáit, és a két formátumot összehasonlítva megnézzük, hogy méret és
olvashatóság szempontjából mennyire térnek el egymástól. Az összehasonlítások
elvégzése után a következő részben a JSON-adatszerkezetek elemzésével
foglalkozunk. A 3.8. kódszöveg adatszerkezete az előző részben
szereplő XML fájl átalakított változata.
3.8. kódszöveg A
kész JSON mintaformátum (email.js)
{
"data":
{
"categories":
{
"category": ["From", "Subject",
"Date"]
},
"row":
{
"items":
[
{
"action":
"alert(’Grace Hopper’);",
"icon":
"img/mail.gif",
"item": ["Grace Hopper",
"<b>BUG Found</b>", "2006-03-31
09:27:26"]
},
{
"action":
"alert(’Pi Sheng’);",
"icon":
"img/mail.gif",
"item":
["Pi Sheng", "Movable type", "2006-01-15 12:32:45"]
}
]
}
}
}
Láthatjuk, hogy ez sokkal kevesebb,
mint az XML változatban, mert a címkék az XML-szerkezettől eltérően
itt nem ismétlődnek feleslegesen. Ne feledjük, hogy ez a fájl sokkal
tömörebb is lehet, csak a jobb olvashatóság kedvéért jelenítettük meg így. A
JSON adatszerkezet megközelítőleg 200 karakterrel rövidebb: összesen 316
karakterből áll, míg az XML formátum 519 karakter hosszú – ami igen nagy
különbség. Ahogy az alkalmazásban szereplő adatok sokasodnak, ez
sávszélesség-problémákhoz vezethet, de ahogy korábban említettük, a JSON-nal
lassabb lehet az ügyféloldali elemzés. Végül el kell dönteni, hogy melyik
formátum használhatóbb az adott alkalmazásban, illetve hogy számunkra melyiket
könnyebb elemezni és írni.
A JSON elemzése
A JSON XHR-ből származó válaszként
való elemzése eltér az Ajax-szal használható összes többi adatcsere-formátum
elemzésétől. Az XML-nél alkalmazott responseXML tulajdonság helyett a responseText tulajdonságot kell használni. Ezt a
tulajdonságot rendkívül egyszerű sima szöveggel vagy tiszta XHTML-lel
alkalmazni, mert egyedül ezt használjuk a válasz értékeként, ahogy a
következő példában is:
document.write(request.responseText);
A responseText tulajdonság JSON-nal történő alkalmazása
szintén egyszerű; csupán annyi a különbség, hogy ki kell értékelni ahhoz,
hogy olvasható legyen az elemzéshez. A válasz kiértékelésével lényegében
létrehozzuk az adat JavaScript-objektumát, amelyet azután az ügyféloldalon a
GUI megjelenítési adataiként használhatunk. Az adatok elemzéséhez először
létrehozzuk a visszahívó függvényt, ellenőrizzük a kérelem készenléti állapotát,
majd kiértékeljük a responseText-et
(lásd a 3.9. kódszöveget).
3.9. kódszöveg Válaszobjektum
létrehozása (ajax.js)
function
onJSONResponse()
{
if(checkReadyState(request, ’loading’) ==
true)
{
eval("var response =
("+request.responseText+")");
}
}
Ahogy azt a fejezet XML-lel foglalkozó
részében tárgyaltuk, a checkReadyState
tagfüggvény két célra használható: a válasz teljes betöltődésének ellenőrzésére,
valamint betöltési üzenet megjelenítésére a felhasználó számára, bármilyen paraméterként
meghatározott HTML-elemben. A válasz teljes betöltődése után az
XHR-ből származó responseText
kiértékelésével kezdjük az elemzést, valamint létrehozunk egy response nevű objektumot
az eredmény számára. Ez az objektum ezután képes bármilyen, a kiértékelés vagy
az adatok elemzése során hozzáadott értéket kijelölni. Kezdjük azzal, hogy kijelöljük
az adatokból a kategóriákat, majd az indexfájlban szereplő body div-hez adjuk azokat (lásd a 3.10. kódszöveget).
3.10. kódszöveg A
JSON-kategóriák elemzése (ajax.js)
//Kategóriák
document.getElementById("body").innerHTML
= "------------<br/>";
document.getElementById("body").innerHTML
+= "<b>Categories</b><br/>";
document.getElementById("body").innerHTML
+= "------------<br/>";
for(var i in
response.data.categories.category)
{
document.getElementById("body").innerHTML +=
å response.data.categories.category[i]
+"<br/>";
}
Láthatjuk, hogy miután
JavaScript-objektummá alakítottuk az adatokat, már könnyű kijelölni azokat.
A tulajdonságértékeket egyszerűen, pont jelöléssel lehet elérni. A 3.10.
kódszövegben olyan kategóriákat jelölünk ki, amelyek tömbök, mivel a category tulajdonságban több
érték szerepelt. A kategóriatömb kijelöléséhez pont jelölést alkalmazunk,
amellyel szó szerint útvonalat rajzolunk a válaszobjektum egy adott tulajdonságához.
Most, hogy megtörtént a kategóriák elemzése
és a body div-ben történő megjelenítése, kijelöljük az elemeket.
Ehhez két for ciklust
kell beágyazni, csakúgy, mint az XML-példában, de a tényleges értékek elemzése
kissé eltér majd a valódi elemek és a jellemzőik esetében. A 3.11. kódszövegre
tekintve megérthetjük, miként elemezzük ezeket az adatokat.
3.11. kódszöveg
JSON-elemek elemzése
//Elemek
document.getElementById("body").innerHTML
+= "------------<br/>";
document.getElementById("body").innerHTML
+= "<b>Items</b><br/>";
document.getElementById("body").innerHTML
+= "------------<br/>";
for(var i in
response.data.row.items)
{
for(var j in response.data.row.items[i])
{
document.getElementById("body").innerHTML +=
å
response.data.row.items[i][j]+"<br/>";
}
document.getElementById("body").innerHTML +=
"------------<br/>";
}
Ahogy korábban említettük, az elemjellemzőket
teljesen eltérő módon jelöljük ki, mint az XML-elemzésnél. Egy egyszerű
for...in ciklussal kijelölhetjük
az összes tulajdonságértéket egy adott objektumon belül. Ezúttal az adatgyűjtés
ezen módszerét használjuk az elemjellemzők és az elemtömbök értékeinek eléréséhez.
A JSON válaszformátumként történő
alkalmazása még hatékonyabb lehet, ha az adatformátumon belül eseménykezelőket
határozunk meg, amelyek a dokumentumra leképezhető bizonyos objektumtípusokat
képviselnek. Ezt nem tárgyaljuk részletesen, de fontos, hogy tudjunk róla, mert
nagyon hasznos lehet a későbbi alkalmazásokban. Elégedjünk meg egy példával,
amely bemutatja, milyen megközelítésben kell szerkeszteni az ilyen adatokat:
"items": [
{"value": "Read
e-mail", "onclick": "displayEmailDetail()"}
]
Most, hogy bővebb ismeretekkel rendelkezünk
az Ajax-válaszok kezeléséről, összpontosítsunk a grafikus felhasználói felület
CSS-sel vagy XHTML-lel történő létrehozására, illetve formázására.