ajax01.qxd
1/22/2007
1:46 PM
Page 1
I rész Az elsõ lépések
1. fejezet Az Ajax bemutatása 2. fejezet A kérelem 3. fejezet A válasz 4. fejezet A válasz leképezése XHTML-lel és CSS-sel
ajax01.qxd
1/22/2007
1:46 PM
Page 2
ajax01.qxd
1/22/2007
1:46 PM
Page 3
1 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.
ajax01.qxd
4
1/22/2007
1:46 PM
Page 4
I. rész • Az elsõ lépések
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
ajax01.qxd
1/22/2007
1:46 PM
Page 5
1. fejezet • Az Ajax bemutatása 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.
5
ajax01.qxd
1/22/2007
1:46 PM
Page 6
ajax02.qxd
1/22/2007
1:46 PM
Page 7
2 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
ajax02.qxd
8
1/22/2007
1:46 PM
Page 8
I. rész • Az elsõ lépések
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 JavaScriptkó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 tartomá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.
ajax02.qxd
1/22/2007
1:46 PM
Page 9
2. fejezet • A kérelem
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.
9
ajax02.qxd
10
1/22/2007
1:46 PM
Page 10
I. rész • Az elsõ lépések
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.
ajax02.qxd
1/22/2007
1:46 PM
Page 11
2. fejezet • A kérelem 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.
11
ajax02.qxd
12
1/22/2007
1:46 PM
Page 12
I. rész • Az elsõ lépések 2.1 táblázat
Az XHR tulajdonságai és azok meghatározása
Tulajdonság onreadystatechange readyState responseText responseXML status statusText
2.2 táblázat
Meghatározás Eseménykezelõ, amely a kérelemobjektum állapotának változásakor indul el. 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ó. A kiszolgálótól érkezõ válasz karakterlánc-változata. A kiszolgálótól érkezõ válasz DOM-megfelelõ dokumentumobjektuma. A kiszolgálótól érkezõ válasz állapotkódja. Karakterláncként visszaadott állapotüzenet.
Az XHR tagfüggvényei és azok meghatározása
Tagfüggvény
Meghatározás 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. Abort()
"é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.
ajax02.qxd
1/22/2007
1:46 PM
Page 13
2. fejezet • A kérelem 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.
13
ajax02.qxd
14
1/22/2007
1:46 PM
Page 14
I. rész • Az elsõ lépések
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 Ajaxvá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 break; case 1: document.getElementById(id).innerHTML break; case 2: document.getElementById(id).innerHTML break; case 3: document.getElementById(id).innerHTML break; case 4: document.getElementById(id).innerHTML return (obj.status == 200); break; default: document.getElementById(id).innerHTML }}
= "Kérelem küldése...";
= "Válasz betöltése...";
= "Válasz betöltve...";
= "Válasz kész...";
= "";
= "Váratlan hiba.";
ajax02.qxd
1/22/2007
1:46 PM
Page 15
2. fejezet • A kérelem 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 readyState-érték
A readyState-értékek jelentése és meghatározása
3
Jelentés Nincs kezdõérték Töltés Töltés kész Interaktív
4
Kész
0 1 2
Meghatározás Az objektumban még nem szerepelnek adatok. Az objektum tölti az adatokat. Az objektum befejezte az adatok töltését. A felhasználó kapcsolatot létesíthet az objektummal, annak ellenére, hogy a töltés nem fejezõdött be teljesen. 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 • Sikeres: 2xx • Átirányítás: 3xx
• Ügyfélhiba: 4xx • Kiszolgálóhiba: 5xx
15
ajax02.qxd
16
1/22/2007
1:46 PM
Page 16
I. rész • Az elsõ lépések
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.
ajax02.qxd
1/22/2007
1:46 PM
Page 17
2. fejezet • A kérelem 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ó.
17
ajax02.qxd
1/22/2007
1:46 PM
Page 18
ajax03.qxd
1/22/2007
1:47 PM
Page 19
3 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 XHRké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:
ajax03.qxd
20
1/22/2007
1:47 PM
Page 20
I. rész • Az elsõ lépések
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 XMLszerkezet 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.
ajax03.qxd
1/22/2007
1:47 PM
Page 21
3. fejezet • A válasz Az alábbi XML-formátum használható, de nem kifejezetten bõvíthetõ, illetve újrahasznosítható megoldás:
<Subject/>
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)
From Subject Date
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 elemek-
21
ajax03.qxd
22
1/22/2007
1:47 PM
Page 22
I. rész • Az elsõ lépések
hez 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)
- BUG Found]]>
- 2006-03-31 09:27:26
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
elembe ágyazott - elemcsoportot láthatunk:
- Grace Hopper
- BUG Found
- 2006-03-31 09:27:26
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,
ajax03.qxd
1/22/2007
1:47 PM
Page 23
3. fejezet • A válasz hogy nem lehet HTML-címkéket ágyazni az XML-elemekbe, mert az elemzõ nem HTMLcí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 () 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: - BUG Found
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 HTMLcímkékkel: - BUG Found]]>
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,
23
ajax03.qxd
24
1/22/2007
1:47 PM
Page 24
I. rész • Az elsõ lépések
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)
From Subject Date - BUG Found]]>
- 2006-03-31 09:27:26
- 2006-01-15 12:32:45
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)
The Response <script type="text/javascript" src="javascript/ajax.js">
ajax03.qxd
1/22/2007
1:47 PM
Page 25
3. fejezet • A válasz
xml | json
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-
25
ajax03.qxd
26
1/22/2007
1:47 PM
Page 26
I. rész • Az elsõ lépések
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 = "------------
"; document.getElementById("body").innerHTML += "Categories
"; document.getElementById("body").innerHTML += "------------
"; var categories = response.getElementsByTagName(’category’); for(var i=0; i"; }
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 += "------------
"; document.getElementById("body").innerHTML += "Items
"; document.getElementById("body").innerHTML += "------------
"; var row = response.getElementsByTagName(’row’); for(var i=0; i
ajax03.qxd
1/22/2007
1:47 PM
Page 27
3. fejezet • A válasz
{ var action = ¯ response.getElementsByTagName(’items’)[i].getAttribute(’action’); var icon = ¯ response.getElementsByTagName(’items’)[i].getAttribute(’icon’); document.getElementById("body").innerHTML += ¯ action +"
"+ icon +""; var items = response.getElementsByTagName(’items’)[i].childNodes; for(var j=0; j"; } } document.getElementById("body").innerHTML += "------------
"; }
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é-
27
ajax03.qxd
28
1/22/2007
1:47 PM
Page 28
I. rész • Az elsõ lépések
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 Adattípus Karakterlánc Szám Logikai érték Tömb
Az egyes adattípusok JSON-megfelelõi JSON ábrázolás "icon": "img/mail.gif" "mynumber": 100 "myboolean": true "items": [ { "action": "alert(’Grace Hopper’);", "icon": "img/mail.gif", "item": ["Grace Hopper", "BUG Found", ¯ "2006-03-31 09:27:26"] },
ajax03.qxd
1/22/2007
1:47 PM
Page 29
3. fejezet • A válasz
{ "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": [
29
ajax03.qxd
30
1/22/2007
1:47 PM
Page 30
I. rész • Az elsõ lépések
{ "action": "alert(’Grace Hopper’);", "icon": "img/mail.gif", "item": ["Grace Hopper", "BUG Found", "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 XMLszerkezettõ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).
ajax03.qxd
1/22/2007
1:47 PM
Page 31
3. fejezet • A válasz 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 = "------------
"; document.getElementById("body").innerHTML += "Categories
"; document.getElementById("body").innerHTML += "------------
"; for(var i in response.data.categories.category) { document.getElementById("body").innerHTML += ¯ response.data.categories.category[i] +"
"; }
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.
31
ajax03.qxd
32
1/22/2007
1:47 PM
Page 32
I. rész • Az elsõ lépések 3.11. kódszöveg
JSON-elemek elemzése
//Elemek document.getElementById("body").innerHTML += "------------
"; document.getElementById("body").innerHTML += "Items
"; document.getElementById("body").innerHTML += "------------
"; 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]+"
"; } document.getElementById("body").innerHTML += "------------
"; }
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.