Generujeme jednoduchý web pomocí XML

XML

Staticky generované weby byly poměrně dlouho v ústraní. Jako by se zdálo, že redakční systém je univerzální řešení, vhodné i pro ty nejmenší prezentace. Poslední dobou se ale začínají statické weby opět prosazovat – jednak díky cloudovým úložištím, které lze použít místo serveru, jednak i kvůli schopnostem HTML.

Weby jsou různé – někdy jsou branou ke komplexnímu informačnímu systému, jedním z jeho rozhraní, jindy jsou přehlídkou grafického nadání svého tvůrce, nebo naopak solidní prezentací firmy, jindy zase užitečnou aplikací. Ale i u těch nejjednodušších webů musíme řešit úkoly jako: jak dostat hlavní nabídku na všechny stránky (rámce už se dneska moc nenosí), jak aktualizovat vzhled webu, aniž bychom museli měnit všechny stránky ručně jednu po druhé, jak vložit na stránky opakující se části (např. naši adresu nebo název firmy), jak si usnadnit práci…

Programátoři jsou tvorové od přírody líní, ale zvídaví, a tak než aby půl hodiny otrocky ručně přepisovali spousty souborů, raději stráví několik hodin vývojem nástroje, který to udělá za ně. Nebo použijí nějaký hotový. Weby taky nemusíme psát ručně – můžeme si pomoci nějakým šikovným generátorem. A právě tvorbu takového generátoru si v dnešním článku ukážeme. Výstupem budou statické (X)HTML stránky.

Nevýhody statického webu jsou zřejmé a často limitující – jaké jsou ale jeho výhody? Proč bychom mohli chtít statické stránky, když můžeme mít dynamické?

  • Offline média: (X)HTML stránky nemusí být umístěné jen na webovém serveru, např. můžeme chtít rozdávat CDčka či USB flash disky svým zákazníkům nebo návštěvníkům konference, a pak je hezké, když uživatel dostane i trochu té grafiky a přehledné navigace místo holých souborů a adresářů.
  • Servery s omezenou funkcionalitou: statické stránky (třeba dokumentaci, návod, směrnice) můžeme vystavit na obyčejný sdílený disk a ten poslouží stejně dobře jako webový server. Statické stránky dále můžeme nahrát i na velmi malá zařízení (např. router s minimem paměti a pomalým procesorem nebo nějaký jednočip), na kterých běží jednoduchý HTTP server (ale na provoz nějakého skriptování už tu není kapacita). Příkladem může být i cloudové úložiště, jako je Amazon S3 – v něm můžete svou statickou prezentaci vytvořit během několika minut.
  • Jednoduchost a odolnost proti výpadkům: čím jednodušší systém bude, tím méně se toho může pokazit. Nemusíte řešit, jestli máte na webhostingu správnou verzi PHP, jestli běží databáze nebo jestli jsou nainstalované všechny potřebné knihovny. Statický web jednou vygenerujete, zkontrolujete a od té doby se na něm nemá co rozbít. Také je možné ho neomezeně škálovat – jednoduše nahrajeme soubory na více serverů – výkon pak předčí i libovolnou noSQL databázi, protože jednodušší už to být nemůže (v krajním případě nahrajeme stránky do tmpfs souborového systému a budou se servírovat přímo z paměti).
  • Bezpečnost: možná už jste narazili na www stránku tvořenou jedním PHP skriptem, jehož jediným úkolem bylo vložit menu a zvolenou stránku na základě GET parametru. Jenže byl tak špatně napsaný, že přes něj šlo získat libovolný soubor ze serveru. Se statickým webem tohle neriskujete, spravovat takový web je proto nenáročné a lze to svěřit leckomu – ne jako programování, kde špatný programátor je jako neřízená střela a může způsobit, že se z vašeho serveru stane doupě spamerů nebo rhybářské centrum pro celou střední Evropu. Také nepotřebujete odborníky na testování nebo revize kódu.
  • Nostalgie: možná taky pamatujete dobu, kdy web začínal a kdy jste na něj pověsili svoji první stránku. Tehdy bylo úplně jedno, že jste nepoužívali žádnou metodiku vývoje a že váš program nestavěl na žádném světoznámém frameworku. Šlo o čistou radost z toho, že se na váš výtvor může podívat kdokoli na světě.

Použité technologie

XML: nebudeme nosit sovy do Athén – webdesignéři jistě znají – jen pro pořádek je nutno uvést, že náš generátor staví na metajazyce XML (vstup, výstup i samotný program je napsaný v XML).

XSL: pro převod vstupních souborů vytvořených uživatelem na hotové www stránky použijeme jazyk XSL, který slouží k transformaci jednoho XML v jiné XML (případně v text – např. si pomocí XSL transformace můžete vygenerovat dokument v LaTeXu a dosáhnout typograficky kvalitního výstupu). Původně byl tento jazyk určen k formátování/vi­zualizaci XML dokumentů, nicméně dnes se používá pro zcela obecné transformace mezi různými datovými formáty a „opravdovému“ programování.

XPath: v rámci našich XSL transformací využijeme dotazovacího jazyka XPath, který nám umožní snadno a přehledně adresovat jednotlivé elementy nebo části XML stromu. Čím je pro relační databáze SQL, tím je pro XML dokumenty a databáze XPath.

Ant: nástroj pro sestavení (build) programu, něco jako GNU Make, ale používaný hlavně ve světě Javy. Ant obsahuje vestavěnou úlohu pro zavolání XSL transformace, takže díky němu můžeme spustit generování s minimem úsilí (nemusíme nic programovat nebo skriptovat, jen deklarujeme, co, kam a pomocí jaké šablony se má převést – a postará se i o další věci jako je kopírování statického obsahu nebo úklid).

První XSL transformace

Ještě než začneme, nainstalujeme si Ant. V linuxových distribucích na bázi Debianu/Ubuntu tak učiníme pomocí příkazu:

aptitude install ant

Ve Fedoře k témuž poslouží:

yum install ant

Abychom měli co transformovat, vytvoříme si nějaký vstupní dokument. Obyčejně se v této fázi vyplatí poctivá analýza a trochu toho přemýšlení, protože formát, který si na začátku definujeme, nás bude provázet možná až do hrobu. Ovšem teď nám o nic nejde, jen tak si hrajeme, takže prostě zbastlíme úplně jednoduchý dokument:

<velmiJednoduchýXmlDokument xmlns="https://trac.frantovo.cz/xml-web-generator/wiki/xmlns/strana">
    <nadpis>Ahoj světe!</nadpis>
    <obsah xmlns="http://www.w3.org/1999/xhtml">

        Lorem ipsum, nějaký text dokumentu, bla <b>bla</b>, bla.
    </obsah>
</velmiJednoduchýXmlDokument>

Dokument popisuje jednu www stránku – její nadpis a obsah. Nyní napíšeme XSL šablonu, která z tohoto obskurního formátu (který jsme právě lehkomyslně stvořili) vyrobí standardní XHTML. Šablona vypadá následovně:

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet version="2.0"
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://www.w3.org/1999/xhtml"
    xmlns:s="https://trac.frantovo.cz/xml-web-generator/wiki/xmlns/strana"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"

    xmlns:fn="http://www.w3.org/2005/xpath-functions"
    exclude-result-prefixes="fn h s xs">
    <xsl:output method="xml" indent="yes" encoding="UTF-8"
        doctype-public="-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN"
        doctype-system="http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd"/>

    <!-- (1) -->
    <xsl:template match="/">
        <html>
            <head>
                <title><xsl:value-of select="s:velmiJednoduchýXmlDokument/s:nadpis"/></title>
            </head>

            <body>
                <h1><xsl:value-of select="s:velmiJednoduchýXmlDokument/s:nadpis"/></h1>
                <p>
                    <xsl:apply-templates select="s:velmiJednoduchýXmlDokument/h:obsah/node()"/>

                </p>
            </body>
        </html>
    </xsl:template>

    <!-- (2) -->
    <xsl:template match="*">

        <xsl:element name="{name()}">
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>

    <!-- (3) -->
    <xsl:template match="h:b">
        <strong><xsl:apply-templates/></strong>
    </xsl:template>

</xsl:stylesheet>

XSL styl (formátovací sada) obsahuje jednotlivé šablony (<xsl:template/>). Pomocí jejich atributu match říkáme, na co se mají aplikovat. První šablona se aplikuje na celý vstupní dokument a postará se o potřebné HTML hlavičky, dále vloží nadpis do titulku i do <h1/>. Vlastní obsah stránky (to, co je uvnitř <obsah/>) už přenechá na ostatních šablonách.

Druhá šablona se aplikuje na všechny elementy a kopíruje je na výstup. Aby to nebyla taková nuda, třetí šablona se stará o <b/> elementy a převádí je na <strong/>. Všimněte si, že přednost mají šablony s užším zaměřením – místo univerzální (2) se na <b/> elementy aplikuje konkrétnější (3).

Nyní přichází ke slovu Ant – pomocí něj zavoláme transformaci a získáme výstup. Výchozím řídícím souborem pro Ant je build.xml, je to něco jako Makefile. V úvodu jsme si slíbili, že to bude jednoduché a deklarativní, tak tedy budiž:

<project name="xhtml-web" default="generuj">
    <target name="generuj">
        <xslt   in="vstup.xml"
                out="výstup.xhtml"

                style="šablona.xsl">
        </xslt>
    </target>
</project>

Všechny tři soubory ( vstup.xml, šablona.xsl a build.xml) máme v jednom adresáři a v něm zadáme příkaz ant. Dostaneme přibližně následující výpis:

Buildfile: ~/ukázka-xslt/build.xml

generuj:
     [xslt] Processing ~/ukázka-xslt/vstup.xml to ~/ukázka-xslt/výstup.xhtml
     [xslt] Loading stylesheet ~/ukázka-xslt/šablona.xsl

BUILD SUCCESSFUL
Total time: 1 second

Během okamžiku nám Ant vyrobil soubor výstup.xhtml s následujícím obsahem:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" "http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Ahoj světe!</title>
</head>
<body>

    <h1>Ahoj světe!</h1>
    <p>
        Lorem ipsum, nějaký text dokumentu, bla <strong>bla</strong>, bla.
    </p>
</body>

</html>

Už i u takto jednoduché úlohy sklízíme první ovoce našeho počínání – když budeme chtít do stránek doplnit třeba odkaz na JavaScript nebo CSS stylopis, doplníme ho jen do XSL šablony a nebudme muset upravovat jednotlivé vstupní dokumenty.

Teď už doopravdy

Po nezbytném „hello world“ příkladu se pustíme do skutečné práce. Naším cílem bude generátor jednoduchých statických webů, na který budeme mít následující požadavky:

  • Ze sady vstupních XML dokumentů (v našem vlastním formátu) vyrobí sadu validních XHTML dokumentů (nebudeme tedy dokumenty převádět po jednom a vyjmenovávat je v  build.xml).
  • Statický obsah (JavaScripty, CSS styly, obrázky) zkopíruje do výstupního adresáře.
  • Do každé stránky přidá záhlaví a zápatí, které definujeme v samostatných souborech.
  • Na každé stránce bude nabídka (navigace) s odkazy na ostatní stránky.
  • Některé stránky v hlavní nabídce nebudou (ale transformují se společně s ostatními).
  • Vytvoříme si „makro“, které bude sloužit k vkládání opakujícího se textu (např. adresa firmy).
  • Automaticky se vyrobí agregované výstupy: RSS, Atom, sitemap.xml.
  • Generátor si poradí s češtinou a mezerami v názvech souborů.

Takže náš generátor bude fungovat asi takhle:

Protože budeme používat i některé vlastnosti z XSLT 2.0, přizveme si na pomoc Saxon (XSLT procesor od Michaela Kaye). Nainstalujeme si také mercurial (bude se nám hodit později ke stažení zdrojových kódů generátoru):

aptitude install ant libsaxonb-java mercurial

Ve Fedoře:

yum install ant mercurial saxon.noarch

Vstupní formát

Vstupní XML formát (pomocí kterého popisujeme stránky) musíme rozšířit, aby odpovídal našim požadavkům:

<stránka xmlns="https://trac.frantovo.cz/xml-web-generator/wiki/xmlns/strana">
    <nadpis>Vítejte na našem webu!</nadpis>

    <perex>Úvodní stránka našeho webu.</perex>
    <pořadí>10</pořadí>

    <text xmlns="http://www.w3.org/1999/xhtml">
        <p>sem píšeme normální HTML značky</p>
    </text>

</stránka>

Perex využijeme v RSS/Atom výstupech (případně bychom ho mohli zobrazovat v title  atributu odkazů). Protože budeme chtít mít nabídku nějak uspořádanou (typicky úvod jako první a kontakt jako poslední), poznačíme si u každé stránky, kolikátá má být v nabídce (mezi čísly je lepší dělat větší mezery, abychom mohli později vložit další stránky mezi ně a nemuseli přečíslovávat).

Společná konfigurace

Dále si navrhneme konfigurační soubor web.conf, který bude obsahovat metadata pro celý náš web. V něm definujeme společné CSS styly a JavaScripty, autora atd. Později sem můžeme přidat třeba klíčová slova nebo další parametrizaci.

<web xmlns="https://trac.frantovo.cz/xml-web-generator/wiki/xmlns/konfigurace">
    <název>Chovatelská stanice tučňáků</název>
    <podtitul>vše pro tučňáky</podtitul>
    <autor>

        <jméno>František Kučera</jméno>
        <email>anonym@example.com</email>
    </autor>

    <!-- Základní URL našeho webu – pro generování RSS/Atom -->
    <url>https://frantovo.cz/projekty/xml-web-generator/demo1/</url>


    <!-- ID našeho webu (každý by si měl vygenerovat svoje) – pro Atom -->
    <uuid>399a714c-956e-444c-a8f4-afe8f0df802a</uuid>

    <!-- Kód našeho webu, použije se jako součást identifikátoru položek v RSS/Atomu -->
    <kod>PokusnyWeb123</kod>

    <!-- Odkazy na JavaScripty a kaskádové styly -->

    <css>css/styl.css</css>
    <js>js/skript.js</js>

</web>

Pokud budeme chtít vložit víc CSS nebo JavaScriptů, nebudeme vymýšlet žádné hlouposti jako oddělování hodnot čárkou, ale jednoduše do web.conf vložíme více elementů <css/> nebo <js/>.

Úprava antovského build.xml

Stránek už máme více a určitě se nám nebude chtít je všechny vypisovat v antovském build.xml, takže si ho trochu upravíme, aby se transformovaly všechny soubory ve vstupním adresáři.

<xslt basedir="${vstup}" destdir="${výstup}" includes="*${vstupníPřípona}" extension="${výstupníPřípona}" style="${šablona}/stránka.xsl">
    <param name="vstupníPřípona" expression="${vstupníPřípona}"/>
    <param name="výstupníPřípona" expression="${výstupníPřípona}"/>

    …
</xslt>

Teď už se pustíme do úpravy XSL šablony:

Vkládání záhlaví a zápatí

Ant volá XSLT procesor a říká mu, jaký vstup (např. index.xml) má transformovat na jaký výstup ( index.xhtml) pomocí jaké šablony ( stránka.xsl). Jenže my potřebujeme kromě vstupu vložit do výstupního XHTML ještě jiný soubor (záhlaví a zápatí). Jak na to? Použijeme funkci document():

<xsl:apply-templates select="document(fn:encode-for-uri(concat($vstup, 'záhlaví', $vsuvkováPřípona)))/s:stránka/h:text/node()"/>

Záhlaví se nachází v souboru záhlaví.inc a má stejnou strukturu jako ostatní stránky. Sestavovací skript ( build.xml) máme parametrizovaný, abychom mohli měnit vstupní/výstupní adresáře nebo přípony souborů – v XSL pak máme tyto parametry přístupné přes proměnné (zde $vstup je vstupní adresář a $vsuvkováPřípona je .inc).

Pomocí <xsl:apply-templates/> aplikujeme šablony (naše výchozí univerzální šablona jen kopíruje, viz úvodní příklad), na externí dokument. Ovšem ne na celý, ale jen na jeho podstrom (nezajímají nás metadata záhlaví, ale jen to, co je uvnitř elementu <text/>). Tohoto výběru dosáhneme pomocí XPath dotazu /s:stránka/h:text/node().

Funkce concat(), jak název napovídá, slouží ke spojování řetězců a funkce encode-for-uri() se postará o kódování URL (tady bychom mohli natvrdo napsat z%C3%A1hlav%C3%AD.inc, ale později budeme potřebovat kódovat proměnlivé texty).

Obsah – nabídka

Vkládat externí dokumenty už umíme. Teď ale potřebujeme načíst celý vstupní adresář, resp. jen soubory se správnou příponou ( xml), přečíst si jejich název/titulek (bude jiný než název souboru) a vložit odkaz do nabídky na všechny stránky. Do šablony proto napíšeme:

<ul id="nabídka">
    <xsl:for-each select="collection(concat('../', $vstup ,'/?select=*', $vstupníPřípona))[s:stránka/s:pořadí]">
        <xsl:sort select="./s:stránka/s:pořadí"/>

        <li>
            <xsl:variable name="xmlSoubor" select="tokenize(document-uri(.), '/')[last()]"/>
            <xsl:variable name="xhtmlSoubor" select="replace($xmlSoubor, $vstupníPřípona, $výstupníPřípona)"/>
            <a href="{fn:encode-for-uri($xhtmlSoubor)}"><xsl:value-of select="./s:stránka/s:nadpis"/></a>

        </li>
    </xsl:for-each>
</ul>

Funkce collection() nám vrátí kolekci dokumentů, skrz kterou budeme iterovat <xsl:for-each/>, ale omezíme se jen na stránky, které mají definované pořadí (když stránka pořadí nemá, znamená to, že ji v hlavní nabídce nechceme), k tomu slouží podmínka [s:stránka/s:pořadí].

Z URI dokumentu si vezmeme název souboru a přepíšeme příponu (výstupní soubory jsou .xhtml, zatímco vstupní .xml).

Na všech stránkách teď máme krásnou nabídku s odkazy na ostatní stránky našeho webu.

XPath dotazy typu /s:stránka/h:text/node() můžeme zhruba přirovnat k projekci v SQL, zatímco XPath dotazy obsahující hranaté závorky [s:stránka/s:pořadí] jsou zase podobné restrikci v SQL (WHERE podmínky). Ovšem neberte prosím toto přirovnání úplně doslova – zde totiž nepracujeme s relacemi, ale se stromovými XML dokumenty.

Píšeme vlastní „makra“

Náš generátor bude podporovat „makra“ (ve skutečnosti to jsou zase šablony), do vstupního dokumentu napíšeme např. <m:adresaFirmy/> a do výstupních XHTML souborů se vloží správná adresa – ta je definovaná pěkně na jednom místě, takže kdybychom se přestěhovali, změníme ji jen v šabloně, resp. definici makra.

Příklad s adresou by byl až urážlivě jednoduchý, tak si ukážeme něco zajímavějšího. Makra si můžeme parametrizovat. Uděláme si tedy makro, které vykreslí měřák:

Do vstupních dokumentů pak budeme psát pouze:

<m:měřák hodnota="95"/>

A do výstupu se nám vygeneruje všechno potřebné XHTML (případně styly nebo JavaScripty, budou-li potřeba). K tomu poslouží následující šablona (v terminologii našeho generátoru „definice makra“):

<xsl:template match="m:měřák">

    <xsl:variable name="hodnota" select="number(@hodnota)"/>
    <xsl:variable name="šířkaGrafu" select="128"/>
    <xsl:choose>
        <xsl:when test="$hodnota &gt;= 0 and $hodnota &lt;= 100">
            <div style="border: 1px solid black; width: {$šířkaGrafu}px; height: 16px; padding: 0px; text-align: center; background-color: #cfc;">
                <div style="margin: 0px; background-color: #A4E666; width: {@hodnota*$šířkaGrafu div 100}px; height: 16px;"></div>

                <p style="margin: 0px; font-size: 12px; position: relative; top: -15px;">
                    <xsl:value-of select="@hodnota"/>/100
                </p>
            </div>
        </xsl:when>
        <xsl:otherwise>

            <xsl:message terminate="yes">Hodnota měřáku musí být nejméně 0 a nejvíce 100 (udává procenta).</xsl:message>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

Nejprve zkontrolujeme, zda hodnota dává smysl – měla by být od nuly do sta a představuje procenta. Když tomu tak není, dáme uživateli najevo, že takhle by to nešlo – k tomu použijeme XSL zprávu. Nastavíme jí terminate="yes", takže generování skončí chybou – místo aby v tichosti pokračovalo a na výstupu pak byly nesmysly. Tento přístup (selhat co nejdříve – dáváme přednost bezchybnosti před robustností) si zde můžeme dovolit, protože uživatel, který vytvořil vstupní data, je nablízku a může chybu okamžitě opravit (což je taky dobře). Kdyby se tento proces prováděl někde na serveru bez asistence uživatele, pravděpodobně bychom se vydali jinou cestou – pokusili se z chyby nějak zotavit a dodat raději nepřesný/nekom­pletní výstup než žádný ( terminate="yes" bychom nepoužili a chybu jen někam zalogovali pro pozdější opravení).

Jen tak mimochodem jsme se přiučili, jak se píše if/then/else větvení v XSL. Nebylo to těžké, že ne?

Agregované výstupy

Na webu se velmi vyplatí poskytovat krmivo pro čtečky v podobě RSS a Atom výstupů. Návštěvníci si přidají náš kanál do čtečky a hned se dozví o každé novince na našem webu, aniž by tam museli chodit a ručně kontrolovat. Náš web je sice jednoduchý a statický a nový obsah na něj budeme přidávat třeba jen jednou za čtrnáct dní, ale není to žádný otloukánek – RSS/Atom bude mít taky, jako všechny ty dynamické weby kolem.

Také vytvoříme sitemap.xml pro Google, aby se mu naše stránka lépe indexovala (ano, mohli bychom mu předhodit Atom, ale když s XSL to jde úplně samo, tak si ukážeme i Sitemap).

Jelikož nezanedbáváme analýzu, muselo nás napadnout, že ve všech třech agregovaných výstupech (RSS, Atom, Sitemap) jsou stejné informace (výpis stránek, ke každé název a odkaz, případně popis). Dává tedy smysl načíst je jen jednou (jednou zpracovat vstupní soubory) a následně z nich vygenerovat tři různé výstupy. Mohli bychom tedy vytvořit nějaký meziformát, který by obsahoval potřebné hodnoty, a následně bychom tento polotovar transformovali do tří vstupů. Ale nebudeme přece trpět NIH syndromem – nebudeme vymýšlet nový vlastní formát, když už tu jeden hotový a standardizovaný je: Atom – použijeme ho jak v roli meziformátu, tak v roli výstupního formátu.

Proces bude tedy vypadat tak, že vygenerujeme nejdříve Atom a z něj potom zylé dva výstupy. Šablonu pro Atom vložíme do samostatného souboru atom.xsl:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
    xmlns="http://www.w3.org/2005/Atom"

    xmlns:s="https://trac.frantovo.cz/xml-web-generator/wiki/xmlns/strana"
    xmlns:k="https://trac.frantovo.cz/xml-web-generator/wiki/xmlns/konfigurace"
    xmlns:j="java:cz.frantovo.xmlWebGenerator.Funkce"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:fn="http://www.w3.org/2005/xpath-functions"

    exclude-result-prefixes="fn s k j">
    <xsl:output    method="xml" indent="yes" encoding="UTF-8"/>

    <xsl:param name="vstupníPřípona" select="'.xml'"/>

    <xsl:param name="výstupníPřípona" select="'.xhtml'"/>

    <xsl:template match="/">

        <feed>
            <title><xsl:value-of select="k:web/k:název"/></title>

            <subtitle><xsl:value-of select="k:web/k:podtitul"/></subtitle>
            <link rel="self" href="{concat(k:web/k:url, 'atom.xml')}"/>
            <link href="{k:web/k:url}"/>
            <updated><xsl:value-of select="current-dateTime()"/></updated>
            <author>

                <name><xsl:value-of select="k:web/k:autor/k:jméno"/></name>
                <email><xsl:value-of select="k:web/k:autor/k:email"/></email>
            </author>
            <id><xsl:value-of select="concat('urn:uuid:', k:web/k:uuid)"/></id>


            <xsl:variable name="konfigurace" select="/"/>
            <xsl:for-each select="collection(concat('../vstup/?select=*', $vstupníPřípona))[empty(s:stránka/s:skrytá) or not(s:stránka/s:skrytá)]">
                <entry>
                    <title><xsl:value-of select="s:stránka/s:nadpis"/></title>

                    <xsl:variable name="soubor" select="replace(tokenize(document-uri(.), '/')[last()], $vstupníPřípona, '')"/>
                    <link href="{concat($konfigurace/k:web/k:url, encode-for-uri($soubor), $výstupníPřípona)}" />
                    <id><xsl:value-of select="concat('urn:', $konfigurace/k:web/k:kod ,':strana:', encode-for-uri($soubor))"/></id>
                    <updated><xsl:value-of select="j:posledníZměna(document-uri(.))"/></updated>

                    <summary><xsl:value-of select="s:stránka/s:perex"/></summary>
                </entry>
            </xsl:for-each>

        </feed>
    </xsl:template>


</xsl:stylesheet>

Zde využijeme konfigurační soubor našeho webu ( web.conf) a načteme si z něj název webu, základní URL pro absolutní odkazy, jméno a e-mail autora.

Pro zjištění data a času poslední aktualizace souboru použijeme jednoduchou funkci napsanou v Javě (ano, i v Javě se dají psát funkce, i když se formálně jmenují metody):

public class Funkce {
        public static Date posledníZměna(String soubor) throws URISyntaxException {
                return new Date(new File(new URI(soubor)).lastModified());
        }
}

V XSL šabloně si ji zpřístupníme pomocí jmenného prostoru xmlns:j="java:cz.frantovo.xmlWebGenerator.Funkce" (obsahuje plný název třídy, ve které jsou statické metody-funkce). A pak ji voláme pomocí: j:posledníZměna(document-uri(.))

Následný převod z Atom formátu do RSS a Sitemapu je triviální. Jen u RSS musíme přeformátovat datum:

<pubDate><xsl:value-of select="format-dateTime(a:updated,
    '[FNn,*-3], [D01] [MNn,*-3] [Y0001] [H01]:[m01]:[s01] [Z]',
    'en',
    'ISO',
    'US')"/></pubDate>

Ne tak úplně statický web

Možná vám tu přeci jen pořád něco chybí. Možná byste chtěli web ještě trochu oživit a provádět nějaké operace na serverové straně. XML dokumenty můžou obsahovat tzv. instrukce zpracování (PI – Processing Instruction), což jsou sekce určené jiné aplikaci než je XML procesor. Od zbytku XML dokumentu je tato sekce oddělena ostrými závorkami a otazníkem. Za první závorkou následuje návěští (tzv. PITarget). Asi vám to už něco připomíná… ano, do dokumentu můžeme zapsat i části PHP kódu, třeba <?php echo("Ahoj z PHP!"); ?>. V XSL šabloně vložíme do výstupu instrukce pro zpracování touto značkou:

<xsl:processing-instruction name="php">echo("Ahoj z PHP!");</xsl:processing-instruction>

Ve výstupním dokumentu se nám pak objeví <?php echo("Ahoj z PHP!"); ?> a tento kód zpracuje jiná aplikace, což je v tomto případě PHP interpret na serveru. Generovat tedy můžeme i dynamické stránky a ušetřit si tak otrocké psaní opakujících se částí kódu.

Závěr

Dnešní článek jsem zaměřil hodně prakticky – cílem bylo ukázat možnosti generování webů pomocí XSLT a inspirovat k dalšímu studiu – cílem nebylo zahltit čtenáře teorií – tu si můžete nastudovat z knih a článků nebo ji vstřebávat za chodu. Kompletní zdrojové kódy si můžete stáhnout z mercurialového úložiště příkazem:

hg clone https://hg.frantovo.cz/xml-web-generator

Více o generátoru se dočtete na jeho stránce: XML Web generátor. Je to svobodný software, můžete studovat jeho zdrojový kód a upravovat si ho. Program by měl být k užitku i těm, kdo se nechtějí učit pokročilé technologie – stačí si upravit vstupní soubory a lehce přizpůsobit šablonu, k tomu nemusíte být misry v XPath dotazech.

Odkazy a zdroje

Franta Kučera působí jako Java vývojář na volné noze. Programování je jeho koníčkem už od dětství. Kromě toho má rád Linux, relační SŘBD a XML.

Věděli jste, že nám můžete zasílat zprávičky? (Jen pro přihlášené.)

Komentáře: 73

Přehled komentářů

KapitánRUM * moc pěkný článek *
ja. Re: Generujeme jednoduchý web pomocí XML
SB Re: Generujeme jednoduchý web pomocí XML
fos4 Re: Generujeme jednoduchý web pomocí XML
Petr Šmíd Re: Generujeme jednoduchý web pomocí XML
blizz Redakčně smazáno
KapitánRUM Re: Generujeme jednoduchý web pomocí XML
Yet Another Anonymous Coward Alternativy
Martin Malý Re: Alternativy
Kibo Pěkné
Martin Soušek článek o XSLT v 21. století?
Inkvizitor Re: článek o XSLT v 21. století?
MarSik Re: článek o XSLT v 21. století?
Ladislav Thon Re: článek o XSLT v 21. století?
Jiří Kosek Re: článek o XSLT v 21. století?
Ladislav Thon Re: článek o XSLT v 21. století?
Opravdový odborník :-) Re: článek o XSLT v 21. století?
Inkvizitor Re: článek o XSLT v 21. století?
alancox Re: článek o XSLT v 21. století?
Jiří Kosek Re: článek o XSLT v 21. století?
keff Re: článek o XSLT v 21. století?
Mike Re: článek o XSLT v 21. století?
Papouch Re: článek o XSLT v 21. století?
AnonymníMyš Redakčně smazáno
AnonymníMyš Re: článek o XSLT v 21. století?
AnonymníMyš Re: Redakčně smazáno
VfB Re: článek o XSLT v 21. století?
j Re: článek o XSLT v 21. století?
VfB Re: článek o XSLT v 21. století?
xx Re: článek o XSLT v 21. století?
Jiří Kosek Re: článek o XSLT v 21. století?
xx Re: článek o XSLT v 21. století?
fos4 Re: článek o XSLT v 21. století?
xx Re: článek o XSLT v 21. století?
František Kučera Re: článek o XSLT v 21. století?
xx Re: článek o XSLT v 21. století?
František Kučera Re: článek o XSLT v 21. století?
xx Re: článek o XSLT v 21. století?
František Kučera Re: článek o XSLT v 21. století?
Jaja a Paja Re: článek o XSLT v 21. století?
František Kučera Re: článek o XSLT v 21. století?
Jiří Kosek Re: článek o XSLT v 21. století?
xx Re: článek o XSLT v 21. století?
fos4 Re: článek o XSLT v 21. století?
xx Re: článek o XSLT v 21. století?
fos4 Re: článek o XSLT v 21. století?
xx Re: článek o XSLT v 21. století?
xx Re: článek o XSLT v 21. století?
Opravdový odborník :-) Re: článek o XSLT v 21. století?
Opravdový odborník :-) Re: článek o XSLT v 21. století?
xx Re: článek o XSLT v 21. století?
Opravdový odborník :-) Re: článek o XSLT v 21. století?
xx Re: článek o XSLT v 21. století?
Jakub Hozak Jekyll
sputnikone Re: Jekyll
Pavel Zajímavá ukázka
Pepa Re: Zajímavá ukázka
Jiří Kosek Re: Zajímavá ukázka
Pepa Re: Zajímavá ukázka
Opravdový odborník :-) Re: Zajímavá ukázka
Pavel Re: Zajímavá ukázka
Opravdový odborník :-) Re: Zajímavá ukázka
František Kučera Objektové vs. značkovací jazyky
xx Re: Objektové vs. značkovací jazyky
j transformace prohlizecem
fos4 Re: transformace prohlizecem
Jiří Kosek Re: transformace prohlizecem
ptica vyhrady k datum v xml a k transformacim
František Kučera Re: vyhrady k datum v xml a k transformacim
emilk Re: vyhrady k datum v xml a k transformacim
František Kučera Novinky
František Kučera Verze 0.3
Franta Re: Novinky
Zdroj: https://www.zdrojak.cz/?p=3486