Delphi - THTMLProducer komponens, avagy felejtse el a TPageProducer-t

Internet 14. rész

forráskód letöltése
Készített Ön már nagyobb internetes alkalmazást? Ha igen, akkor valószínűleg már észrevehette, hogy a TPageProducer komponens bizony nehézkesen alkalmazható és tudása sem a legnagyobb komolyabb munkákhoz.

Probléma az is, hogy komponensenként csak egy HTML állományt tárolhat, de ha a kezelendő web site-on több száz lap található, akkor a programban már nehezen lenne kezelhető több száz TPageProducer komponens. Ez mondjuk még megoldható, hogy futási időben töltjük be az egyes HTML lapokat.

Másik nagy probléma, hogy egy-egy web site-on sokszor található azonos web lap részlet. Például, ha van néhány olyan oldal, ahová szeretnénk kiírni az aktuális dátumot és ehhez mondjuk elhelyezünk a web lapon egy #datum nevű címkét, akkor ezt minden egyes esetben fel kell dolgozni. Ez viszont teljesen felesleges, mivel az aktuális dátum minden web lapon ugyanúgy kerül kiírásra, így sokkal jobb lenne, ha ezt a címkét elegendő lenne csupán egyszer leprogramozni.

Mellékelt példában készítünk egy THTMLProducer nevű komponenst, mely igen nagymértékben leegyszerűsíti a web lapok dinamikus előállítását. A mellékelt két példaprogram megnyitása előtt szükséges az alábbi tennivalókat elvégezni, hogy azok használhatóak is legyenek:
- A HTMLProducer.pas-ban lévő komponenst telepíteni kell a Delphi alá.
- A Unit1.pas-ban található HTMDIR konstans értékét kérjük írja át, hogy az a könyvtár legyen megadva, ahová a példaprogramot másolta.
- A Unit1-ben található HTMLProducer1 komponens DirPath property-ében található elérési útvonalat módosítsa úgy, hogy az Ön által másolt példaprogram Tmp könyvtárára mutasson.

Ezeket a lépéseket a második (Step02) példaprogramnál is meg kell tenni.
A program lefordítása után azt át kell másolnia abba a könyvtárba, ahonnan futtatni szokta az internetes alkalmazásokat (pl: C:\InetPub\Scripts).

A példaprogramokat kipróbálni a következő módon lehet a fentiek elvégzése után: indítson el egy böngészőt (a példaprogramok és a mellékelt web lapok Internet Explorer-hez készültek!), majd a böngészőbe írja be a következő címet: http://localhost/Scripts/Project1.exe

A localhost helyett a saját rendszerében használt domain nevet használja.
A Scripts könyvtár név szintén módosulhat a rendszerétől függően.


Ezek után nézzük, hogy mit is tud a THTMLProducer komponens.

Elvárásaink ettől a komponenstől a következők lennének:
- Ha több feldolgozandó web lapban azonos címkéket talál, azokhoz mindig ugyanaz a rutin legyen lefuttatva. A bevezetőben említett dátum kiírási problémát ezzel tudjuk megoldani.
- Ha több web lapot szeretnénk egymásba ágyazni, akkor ehhez ne kelljen új komponenst használni, hanem ezt a THTMLProducer tegye meg automatikusan. Ehhez egy rekurzív eljárást használjon, így tetszőleges mélységig egymásba ágyazhatunk web lapokat. Ez a funkció akkor hasznos, ha van egy olyan web lap részletünk, melyre több helyen is szükségünk lehet. Gondoljuk például egy olyan web site-ra, ahol többféle terméket több web lapon lehet megrendelni. Ekkor a megrendelőlap ugyanúgy néz ki minden oldalon, csupán a rendelendő termék neve változik. Ekkor létrehozhatunk tetszőleges tartalmú web lapokat és a megfelelő helyre egyszerűen bemásoltatjuk a megrendelő lapot tartalmazó állományt.

Nézzük most a HTMLProducer.pas-t, ahol a komponens található.

A készítendő web lap létrehozásához egy Content nevű függvényt hozunk létre. Ennek egyetlen sztring paraméterében kell majd megadnunk a feldolgozandó HTML állományt.

Létrehoztunk egy FHTMLFile nevű változót, melyben az aktuálisan feldolgozandó állományt tároljuk el.
A Content nevű függvényben először átmenetileg egy lokális változóba elmentjük a FHTMLFile tartalmát, majd értékül adjuk az újat. Ezek után kerül meghívásra a Process függvény, mely elvégzi a tényleges feldolgozást. Miután végzett, visszatérési értékként megkapjuk a végleges web lapot, melyet a Content függvény is visszaad. Végül visszaállítjuk a FHTMLFile változó eredeti értékét.

Nézzük, hogyan is történik a feldolgozás a Process függvényben.

Itt találunk egy lokális változót, mely nem mást, mint a már jól ismert TPageProducer komponens. Mivel a TPageProducer-nek megvan az a képessége, hogy a feldolgozandó web lapról kikeresi a címkéket, melyeket tetszőleges szövegre cserélhetjük le, így felhasználjuk ezt a komponenst a saját komponensünkön belül, hogy a címke kereső és cserélő funkciót már ne kelljen leprogramoznunk.

Tehát első lépésként létrehozunk egy TPageProducer komponenst, melybe a HTMLFile property-n keresztül megadjuk az aktuálisan feldolgozandó HTML állományt.

Ha a TPageProducer komponens címkét talál a feldolgozás közben, akkor létrejön az OnHTMLTag eseménye. Így ezt fel kell használnunk, ezért hozzárendelünk egy DoHTMLTag nevű eseménykezelő eljárást.

Más teendőnk nem marad, mint hogy meghívjuk a TPageProducer komponens Content függvényét, mely feldolgozza a web lapot és egyetlen sztringként visszaadja annak a tartalmát. Ezt az sztringet adjuk mi is a Process függvényünk visszatérési értékének.

Legvégül megszüntetjük a létrehozott TPageProducer komponenst a Free eljárás hívásával.


Következő lépésként most vizsgáljuk meg, hogy mi is történik akkor, ha egy címkét talál a TPageProducer komponens feldolgozás közben. Ekkor létrejön az OnHTMLTag eseménye, amelyhez a DoHTMLTag eljárást rendeltük. Nézzük, hogyan is működik ez az eljárás.

A THTMLProducer komponensünk használatakor be kell tartanunk egy olyan szabályt, hogy bár web lapon tetszőleges nevű címkék használhatóak, de mostantól az #include nevű címke egy fenntartott kulcsszó lesz. Ha ugyanis ilyen nevű címkét helyezünk el a web lapon, akkor a komponensünk ezt olyan parancsnak értelmezi, hogy itt most egy új web lapot kell beágyaznia a feldolgozandó web lapba.

Ennek megfelelően a DoHTMLTag eljárás először ellenőrzi, hogy a talált címke egyezik-e az "include" szóval. Ha igen, akkor megkezdődik az új web lap beágyazása.

Az "include" címke használata a következő: ha szeretnénk egy web lapba egy másikat beágyazni, akkor az "include" címke megadása után még két paramétert kell megadnunk. Az egyik arra vonatkozik, hogy a beágyazandó web lap melyik könyvtárban található, a másik pedig az állomány nevét fogja meghatározni. Ennek megfelelően lehet a következő címke:
#include path=TMPDIR file=index.tmp.
Látható, hogy a könyvtár nevét a "path" nevű paraméter tárolja és az is észrevehető, hogy nem egy valós elérési útvonalat adtunk meg, hanem csupán egy azonosítót, egy alias-t. Ehhez majd programból fogjuk hozzárendelni a tényleges elérési útvonalat. A másik paraméter "file" névvel szerepel. Itt megadjuk a beágyazni kívánt állomány nevét.

A THTMLProducer komponensben létrehoztunk két TStringList típusú property-t is. DirAlias és DirPath néven. A DirAlias-ban sorolhatjuk fel azokat az azonosítókat, melyekkel elérési útvonalakat szeretnénk azonosítani. Fenti példában megadtunk egy TMPDIR nevű azonosítót is. A DirAlias property-ben kell tehát megadnunk ezt az azonosítót, majd a DirPath-ban megadhatjuk a hozzátartozó tényleges elérési útvonalat.

Erre a bonyolításra azért van szükségünk, mert így nem kell állandóan a web lapokra begépelnünk a teljes elérési útvonalat, arról nem is beszélve, ha mondjuk szeretnénk megváltoztatni azt. Ilyen esetben elegendő csupán egyszer, egy helyen megadnunk az új elérési útvonalat és nem kell az összes web lapunkat módosítani.

Térjünk vissza a DoHTMLTag eljáráshoz. Tehát ha azonosítjuk az "include" címkét, akkor a kapott "path", illetve "file" paraméterekből, valamint a DirAlias és DirPath property-komponens segítségével meghatározhatjuk azt az állományt, melyet szeretnénk beágyazni az aktuális web lapra.

A beágyazás előtt szintén egy lokális változóba (prevhtml) eltároljuk az aktuálisan feldolgozás alatt álló web lap nevét. Majd a beágyazandó web lapot tesszük aktuálissá és egyszerűen meghívjuk ismét a Process eljárást.

Ez nem más, mint egy rekurzív eljárás hívás. Ekkor a Process létrehoz egy újabb TPageProducer típusú komponenst a lokális változójába, majd feldolgozza azt a DoHTMLTag eljárás segítségével, amely ha találna egy újabb "include" azonosítót, akkor ismét folytatódna a rekurzív állomány feldolgozás, mindaddig, amíg vannak feldolgozandó címkék.

Nézzük most a DoHTMLTag eljárás másik ágát, vagyis azt az esetet, amikor a talált címke nem az "include" szó. Ekkor van a komponensnek szüksége "külső" segítségre. Mivel azt már nem tudhatja, hogy az egyedi címkéket milyen tartalomra kell kicserélnie, ezért itt létrehozunk egy saját eseményt OnCustomHTMLTag névvel.

Mivel az állományok feldolgozása rekurzív, így nem is tudhatjuk, hogy a talált címke melyik állományban is van. Erre nincs is szükségünk, ha betartunk egy újabb szabályt: bármely web lapot is készítjük, minden címkének egyedinek kell lennie kivéve, ha azonos funkciót szeretnénk végrehajtatni. Erre a bevezetőben említett dátum kiírási probléma felel meg. Vagyis ha több web lapra is szeretnénk kiíratni az aktuális dátumot, akkor elegendő ezekre a web lapokra mondjuk a #datetime címkét elhelyezni. Ekkor bármelyik web lap is legyen feldolgozva, a #datetime címkére mindig ugyanaz a funkció hajtódik végre, vagyis ez a címke az aktuális dátum sztringjére lesz kicserélve.

A címkék egyszerűbb kezelésének érdekében létrehozunk egy harmadik TStrignList típusú property-t is a THTMLProducer komponensen belül, CustomTagList névvel.
Itt felsorolhatjuk a web lapjainkon előforduló címkék neveit.

Amikor a DoHTMLTag eljárás egy címkét talál, mely nem az "include" szó, akkor ebben a property-ben fogja keresni a talált szót és a generált eseményben paraméterként fogja megadni az adott címke sorszámát.

Ehhez az eseményhez viszont kell készítenünk egy saját típusú eseményt. Ez lesz a TCustomHTMLTagEvent típus, melyet az OnCustomHTMLTag eseménynél használunk fel.
Így az esemény első paraméterében a CustomTagList-ben lévő címke sorszámát kapjuk. Második paraméterként megkapjuk az adott címkéhez esetlegesen tartozó paramétereket. Majd a harmadik paraméter lesz az a sztring, melyre az adott címkét kell lecserélni.


Ezek után nézzük most a Unit1.pas-t, valamint azt, hogy miként is használható a komponensünk.

Első lépésként tehát fel kell sorolnunk a DirAlias property-ben azokat az azonosítókat, melyeket a web lapjainkon használunk az alkönyvtárak azonosítására, majd a DirPath property-ben soroljuk fel az azonosítókhoz tartozó könyvtárakat.

A mellékelt példában csupán egy ilyen könyvtárunk van most, méghozzá a TMP könyvtár, ahol olyan állományokat tárolunk, melyeket majd a web lapokra szeretnénk beágyazni.

Következő lépésként a CustomTagList property-ben megadjuk azokat a címkéket, melyeket a web lapokon használunk. Ha ez megvan, akkor létrehozzuk a komponens OnCustomHTMLTag eseményét.

Itt felhasználva az első Index nevű paramétert egy CASE utasítással elágaztatjuk a programunkat, mivel az Index paraméter fogja megmondani, hogy a CustomTagList-ben felsorolt címkék közül most melyiket is találata meg a komponensünk, egy tetszőleges web lapban.

Ha tehát a "datetime" címke kerül elő valamely web lapból, akkor a cserélendő szöveg (ReplaceText paraméter) az aktuális dátumot és időpontot kell, hogy tartalmazza.

Ha pedig egy "day" nevű címke kerül elő, akkor az aktuális nap nevét adjuk vissza.


A programhoz két akciót hozunk létre. Az első lesz az alapértelmezett, vagyis ha a programot úgy hívjuk meg, hogy: http://localhost/Scripts/Project1.exe

Ekkor a programhoz mellékelt index.htm web lapot jelenítjük meg feldolgozás után.
Ebbe a web lapba két címkét helyeztünk el: az egyik egy "include", mely az index.tmp állományt kell, hogy bemásolja a web lapra, a másik pedig egy "datetime" címke. Ennek a helyén az aktuális dátumot, időt kellene majd látnunk a web lapon.

Létrehozunk még egy link-et is a web lapon, ahol is a programunk második akcióját hívjuk meg.
Itt a mellékelt link.htm állományt jelenítjük meg.

A link.htm-be szintén találunk egy "datetime" címkét. Valamint egy állomány beágyazást, mely most a day.tmp lesz a TMP könyvtárból.

Ez a day.tmp tartalmaz egy újabb címkét, mely a "day" címke lesz. Ha minden jól megy, akkor ennek a címkének a helyén kell megjelennie az adott nap nevének.



A második példaprogramban (Step02 könyvtár) bemutatjuk a THTMLProducer komponens azon lehetőségét is, hogy egy adott címke (jelen esetben a "htm") feldolgozásakor lehetőség van arra is, hogy ismételten meghívjuk ugyanannak a THTMLProducer komponensnek a Content függvényét, függetlenül attól, hogy a komponens épp egy állomány feldolgozása közben van.

Ezt azért tehetjük meg, mert a komponens minden esetben menti egy lokális változóba (prevhtml) az aktuálisan feldolgozandó állomány nevét, így bármikor lehetősége van rá, hogy egy új feldolgozást is elvégezzen.

Ennek az a nagy előnye, hogy bármilyen bonyolult alkalmazást is készítünk a programunkban, elegendő lesz egyetlen egy THTMLProducer komponens minden esetre.



A komponens jelenlegi formájában tehát alkalmas arra, hogy tetszőleges mélységben egymásba ágyazzon web lapokat, valamint arra, hogy a web lapokon található címkéket egységes dolgozza fel.

A komponens rekurzív feldolgozási módszere miatt talán kissé bonyolult algoritmust kíván, mely elsőre talán nem is tekinthető át egyszerűen. De általánosan igaz, hogy egy bonyolult algoritmust ugyan nehezebb elkészíteni, viszont használatával egyszerűsödik, gyorsabbá válik munkánk.

Cégünk web lapjait kezelő szoftverben is megtalálható a THTMLProducer komponens, pontosabban annak egy továbbfejlesztett változata.
A komponens által igen leegyszerűsödött a web lapok készítése, karbantartása.
Csak egyetlen példát említve: majdnem minden web lapunkon megtalálható baloldalt egy kis bejelentkező ablak. Ennek a bejelentkezési ablaknak a HTML kódja egy külön állományban található és egy egyszerű "include" címke segítségével történik az egyes web lapokra való beillesztése. Mivel ez a bejelentkezés ablak nagyon sok web lapon szerepel, így nyilván nem lenne járható út, hogy minden egyes web lapra bemásoljuk a HTML kódot.
Arról nem is beszélve, ha szükség lenne a bejelentkező ablak kinézetének változtatására, akkor ezt csupán egyetlen állományban kellene elvégeznünk és máris az összes web lapunk tartalma megváltozna.


A mellékelt példában található komponens valódi alkalmazásához persze még nem árt jó néhány kiegészítés. Vagyis a jövő héten még jobban bonyolítani fogjuk a THTMLProducer komponenst.

Internet cikksorozat