Kliens oldali XSLT

Generáljunk XML-eket HTML helyett.

Avagy az oldal összerakásával terheljük inkább a látogató böngészőjét a szerver helyett.

Néha egész érdekes dolgokat lehet látni, ha az ember - szakmai ártalomból, vagy csak egyszerű kíváncsiságból - beleles egyes oldalak forrásába. Az ilyen oldalak közé tartozik a The World of Warcraft Armory is. Az első pillantásra elég bonyolultnak tűnő oldal mögött meglepően kicsi (5 soros) XML fájl van. Legalábbis látszólag. Természetesen az XSLT áll a dolog mögött, aminek a szerver oldali alkalmazásáról már réges-régen ejtettem pár szót. Nézzük akkor most meg, hogy kliens oldalon mit művelhetünk vele:

Az alapok

Amire szükségünk lesz az egy XML és egy XSL fájl. A rendszerben valószínűleg az XSL fájlok statikusak lesznek, az XML-ek pedig szerver oldalon fognak generálódni. Nézzünk egy egyszerű blog példát kezdésnek:

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="index.xsl"?>
<page>
    <post url="http://example.com/">
        <name>A bejegyzés címe #1</name>
        <content>
            <p>A bejegyzés tartalma #1</p>
        </content>
        <author url="http://example.com/">író #1</author>
        <tags>
            <tag url="http://example.com/">tag #1</tag>
            <tag url="http://example.com/">tag #2</tag>
        </tags>
    </post>
    <post url="http://example.com/">
        <name>A bejegyzés címe #2</name>
        <content>
            <p>A bejegyzés tartalma #2</p>
        </content>
        <author url="http://example.com/">író #1</author>
        <tags>
            <tag url="http://example.com/">tag #3</tag>
            <tag url="http://example.com/">tag #4</tag>
            <tag url="http://example.com/">tag #5</tag>
        </tags>
    </post>
</page>

Gyakorlatilag bármilyen XML-t használhatunk, az oldal akár lehetne egy RSS feed is, amit a megfelelő XSL fájllal formálunk weboldal alakúvá. Esetünkben ez a fájl valahogyan így néz ki:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"/>
    <xsl:template match="page">
        <html xmlns="http://www.w3.org/1999/xhtml">
            <head>
                <title>XSL teszt</title>
            </head>
            <body>
                <div id="container">
                    <xsl:apply-templates/>
                </div>
            </body>
        </html>
    </xsl:template>
    <xsl:template match="post">
        <div class="post">
            <h2><a href="{@url}"><xsl:value-of select="name/text()"/></a></h2>
            <ul class="post-tags">
                <xsl:for-each select="tags/tag">
                    <li><a href="{@url}"><xsl:value-of select="text()"/></a></li>
                </xsl:for-each>
            </ul>
            <div class="post-content"><xsl:copy-of select="content"/></div>
        </div>
    </xsl:template>
</xsl:stylesheet>

A transzformáció az első illeszkedő <xsl:template> blokk végrehajtása után leáll (esetünkben ez az <xsl:template match="page"> kezdetű blokk). Ahhoz, hogy további template blokkokat hajthassunk végre a jelenlegi elemen (esetünkben ez az XML <page> tagje), vagy annak gyerekein, az <xsl:apply-templates/> taget kell használni (ennek van egy select="" tulajdonsága, amivel még szűkíthetjük a node-okat, amin szeretnénk végrehajtani transzformációt).

A <post> tagre illeszkedő template-ben látható példa arra, hogy hogyan tudunk egy tulajdonságnak értéket adni ({@url}), hogyan lehet sima szöveget kinyerni az eredeti XML-ből (<xsl:value-of select="name/text()"/>) valamint arra, hogyan lehet egy XML részt egy az egyben átmásolni az eredeti XML-ből (<xsl:copy-of select="content"/>). Hosszasan lehetne magyarázni, hogy akkor most ez hogy is van és egyébként is milyen eszközök állnak még a rendelkezésre, de mivel már születtek erről leírások erre és erre (meg még sok egyéb helyen is biztos), ezért ugorjuk át az unalmas részleteket, és nézzünk valami izgalmasabb dolgot, nevezetesen azt, hogy mire is lehet ezt az XSLT dolgot használni?

Többnyelvűsítés

Hogyan is többnyelvűsítünk olyan adatokat a weboldalon, amik statikusan bele vannak írva a sablonba? Például ez a dolog valahogy úgy történhet meg, hogy van egy (optimális esetben minél rövidebb nevű) függvényünk, ami megkapja paraméterként a szöveget és ha van hozzá az adott nyelven fordítás, akkor megjelenítni, ha nincs, akkor pedig kiírja az eredetileg kapott szöveget (vagy bármi más feltűnő szöveget, hogy szegény fordító lássa, hogy ott még hiány van). A függvény maga meg valószínűleg adatbázisból dolgozik, esetleg az adatbázisból generálódik egy PHP, XML vagy egyéb szöveges formátumú fájl cache-elési szándékkal.

Ha már mindenképpen generálunk mondjuk egy XML fájlt ezekből az adatokból, akkor miért ne lehetne azt csinálni, hogy az XSLT-t segítségül hívva rakjuk be a megfelelő helyre a megfelelő nyelvű szöveget? Nézzük is az új XML fájlunkat:

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="multilang.xsl"?>
<page lang="hu"/>

A felesleget kiszórtam belőle, mivel valószínűleg az XML-be csak dinamikus adatok kerülnek már a megfelelő nyelven, úgyhogy az a része minket most nem érdekel. Emellett kapott egy extra tulajdonságot a <page> tag (lang="hu"). Szükségünk lesz még egy második XML fájlra, ami az oldal megjelenítéséhez szükséges statikus szövegeket tartalmazza:

<?xml version="1.0" encoding="utf-8"?>
<strings>
    <string id="text-1">Valami szöveg</string>
    <string id="text-2">Valami másik szöveg</string>
</strings>

...és természetesen egy XSL fájlra, a megfelelő kimenet érdekében:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"/>
    <xsl:variable name="lang" select="/page/@lang"/>
    <xsl:variable name="data" select="document(concat('data_',$lang,'.xml'))"/>
    <xsl:template match="page">
        <html xmlns="http://www.w3.org/1999/xhtml">
            <head>
                <title>XSL teszt</title>
            </head>
            <body>
                <h1><xsl:value-of select="$data/strings/string[@id='text-1']"/></h1>
                <p><xsl:value-of select="$data/strings/string[@id='text-2']"/></p>
            </body>
        </html>
    </xsl:template>
</xsl:stylesheet>

Az előző kódhoz képest lett pár új dolog. Az <xsl:variable> segítségével adhatunk változóknak értéket, amiket később a $változónév formában érhetünk el. Ezen kívül megjelent pár XSL függvény is, a document() és a concat(). A concat() egyszerű string összefűzés, a document() segítségével pedig egy külső XML-t tölthetünk be (így a változón keresztül elérhetjük a benne lévő adatokat).

És a SEO?

Persze, szép dolog szétválasztani a nyers adatokat, a statikus, többnyelvű szöveget a megjelenítéstől, és mintezt kliens oldalon össszerakni, de mit sem ér, ha a keresők nem tudnak vele mit kezdeni. Nem látok bele a keresőrobotok lelki világába, de abból kiindulva, hogy az "armory" szóra a bevezetőben említett oldal amerikai párja jön fel a Google-ben első találatként, arra lehet következtetni, hogy különösebben nem viseli meg őket a dolog. Ha az oldal tárolt változatát is megnézzük, észre lehet venni, hogy a forrásban már az XSL transzformáció utáni állapotot mutatja (és mellesleg a Yahoo!-val és a Live Search-el kapcsolatban is hasonló a helyzet), azaz szerintem az XML+XSLT oldalak (amiknek a kimenete HTML) ugyanúgy viselkednek kereső-optimalizációs szempontból nézve, mint a sima HTML oldalak.

Ennyit mára. Folyt. köv.

Hozzáfűznél valamit?

Dobj egy emailt a blog kukac deadlime pont hu címre.

Feliratkoznál?

Az RSS feed-et ajánljuk, ha kedveled a régi jó dolgokat.