Hlavní navigace

Cocoon v příkladech: Pracujeme s XML databázemi

Pavel Sýkora

Zatím jsme v Cocoonu zpracovávali výhradně kratší XML soubory (do velikosti několika KB). Potřebujeme-li ovšem publikovat pár kilobajtů, které vybíráme z většího XML souboru, dosud představené metody zpracování (např. vybírat ta data pomocí XSL transformace) rozhodně nepatří k efektivním. Pro tyto účely je nejvýhodnější použít nativní XML databázi. Ukážeme si to na příkladu databáze poštovních směrovacích čísel sídel naší republiky.

XML databáze navíc poskytují snadnou možnost změny zdrojových XML dat, protože podobně jako relační databáze obsahují standardní prostředky nejen na efektivní získávání dat, ale i na jejich modifikaci.

Nativní XML databáze

Cocoon verze 2.1.3 obsahuje pseudoprotokol xmldb pro přístup do XML databází poskytujících XML:DB API, nicméně žádná taková databáze v něm obsažena není. V polovině února však vyšla verze 2.1.4, která (mimo jiné) obsahuje vestavěnou databázi Xindice verze 1.1 RC1 a některé nové komponenty (např. transformátor XMLDB). Jinou možností by bylo použít externí (tj. nikoliv vestavěnou) databázi. Pro naše účely bude ale asi nejvhodnější, když si do instalace Cocoonu 2.1.3, kterou jsme používali v předchozích příkladech, sami vestavíme jinou open source nativní XML databázi: eXist verze 1.0 beta 1. Navíc si tak ukážeme obecný způsob, kterým je možné rozšiřovat funkcionalitu Cocoonu.

Rozšiřujeme možnosti Cocoonu

Cocoon lze poměrně snadno rozšiřovat tak, že nakopírujeme potřebné knihovny jar mezi ostatní, které u zkompilované verze Cocoonu najdeme v adresáři build/webbapp/WEB-INF/lib. Dále bývá obvykle nutné upravit soubory cocoon.xconf a (nebo) web.xml v adresáři build/webapp/WEB-INF. V souboru cocoon.xconf je definováno kromě jiného mapování tříd na komponenty (někdy to lze udělat pouze v mapě aplikace), deklarace logicsheetů apod. Pro náš příklad musíme alespoň přidat driver pseudoprotokolu xmldb pro databázi eXist (bude se používat takto: xmldb:exist://...) včetně jeho mapování na konkrétní třídu a generátor XQuery. Databáze eXist obsahuje ale i další komponenty (logicsheet pro XSP,transformátor XMLDB aj.). Pro zjednodušení jsou všechny potřebné soubory zabaleny v archivu cocoon-2.1.3_exist-1.0b1.tgz (cca 2 MB). Archiv obsahuje potřebné knihovny jar, konfigurační soubory, klienta databáze pro administraci, soubory pro náš příklad, a také připraví adresář build/webapp/WEB-INF/data, do kterého si databáze eXist bude ukládat kolekce indexovaných XML dat. Archiv je nutné rozbalit v základním adresáři Cocoonu (standardně ~/cocoon-2.1.3). POZOR! Rozbalením archivu přepíšete původní soubory cocoon.xconf a web.xml (jen ty „zkompilované“). Pokud jste v nich ale udělali nějaké změny, nezapomeňte si je předtím uschovat.

Spuštění databáze a příprava dat

Databáze se nyní bude spouštět automaticky s Cocoonem. Prostě jen spustíte (nebo restartujete) Cocoon. Při jeho prvním startu s databází by se měla objevit i hlášení o tom, že se vytváří prostor pro XML data a indexy. Úroveň logování databáze eXist je nastavena na „INFO“, takže později při práci s příkladem lze například lehce sledovat dobu odezvy databáze.

Příklad najdete v adresáři build/webapp/psc. V souboru psc.xml je databáze obcí a jejich částí (přes dvanáct tisíc prvků <sidlo>) s atributy PSČ a krajem, kam obec patří. Tento soubor byl získán ze souboru ulice.xml, který je veřejně přístupný na serveru adres Ministerstva vnitra. Soubor byl pak zkonvertován jednoduchým stylesheetem ulice2psc.xsl . Soubor psc.xml je nutné nejdříve uložit do databáze. Ta je nastavena tak, aby kromě Cocoonu spolupracovala i se svým klientem přes protokol XML-RPC. Máme-li tedy již spuštěnou databázi (resp. Cocoon s databází), můžeme spustit databázového klienta z hlavního adresáře Cocoonu ( standardně  cocoon-2.1.3):

java -jar start.jar client

Po odkliknutí přihlašovacího okna (bez hesla) je spuštěn klient (zatím jej uvidíte bez kolekce „ psc“):

Klient databáze eXist

Protože XML databáze spravuje data v kolekcích (odpovídá to zhruba adresářům souborového systému), uložíme soubor psc.xml do kolekce „ psc“. Vytvoříme tedy kolekci s názvem „ psc“ a do ní vložíme soubor psc.xml. Můžeme použit GUI nebo příkazovou řádku klienta. Na ní potřebný dialog vypadá takto (vstup uživatele je zvýrazněn):

exist:/db> mkcol "psc"
created collection.
exist:/db> cd "psc"
exist:/db/psc> put "build/webapp/psc/psc.xml"
storing document psc.xml (1 of 1) ...done.
parsing 833038 bytes took 10820ms.
parsed 833038 bytes in 10820ms. 

Nyní můžete klienta ukončit (CTRL+Q) nebo vyzkoušet databázi dotazem na záznam obce Slavkov. Stisknutím CTRL+F (nebo v menu Tools/Find) otevřete nové okno, do jehož části „XQuery“ zadejte (bez uvozovek) tento výraz XPath: „ //sidlo[.='SLAVKOV']“. Po odeslání (Submit) by v části „Results“ mělo být zhruba (zanedbal jsem prvek <exist:match>) to­to:

<sidlo kraj="MORAVSKOSLEZSKÝ" psc="747 57">
SLAVKOV

</sidlo>

Nyní máme připraveno vše pro naši aplikaci.

Aplikace: databáze PSČ

Aplikace je velmi jednoduchá. Spusťte Cocoon a v prohlížeči zadejte (bez uvozovek) toto URL: „ http://localhost:8888/psc/“. Nezapomeňte na ukončující lomítko. Zobrazí se jednoduchý formulář. Do formuláře se zadává libovolná část jména obce nebo její části (pouze z České republiky) a po odeslání (a vrácení výsledku) se pod tímtéž formulářem objeví seznam obcí (resp. jejich částí) se směrovacími čísly. Níže je uvede výsledek hledání řetězce „SLAVKOV“ (zadávejte bez uvozovek):

PSČ - výsledek

O formulář i jeho zpracování se stará soubor hledej-psc.xq zapsaný v XML Query (XQuery):

xquery version "1.0";

declare namespace request=
  "http://exist-db.org/xquery/request";
declare namespace util=
  "http://exist-db.org/xquery/util";

<html>

 <head>
  <title>Hledání</title>
 </head>
 <body>
  <h3>Hledání PSČ</h3>

  <form action="hledej-psc">
   <p>Zadejte část názvu sídla:
    <br />
    <input type="text" name="sidlo" id="sidlo"/>
   </p>
   <p>

    <button type="submit">Odeslat</button>
   </p>
  </form>
{
let $sidlo:=request:request-parameter("sidlo","")
  return
    if (string-length($sidlo) = 0) then
      <p>Řetězec nebyl zadán!</p>
    else
      <div>

       <p><em>Výsledky hledání pro
       <strong>*{$sidlo}*:</strong>
       </em></p>
       <ul>
       {
         let $query := concat(
                          "//sidlo[contains(.,'",
                          $sidlo,
                          "')]"
                       )
         for $s in util:eval($query)
           return
           <li>{$s}</li>

       }
       </ul>
       </div>
}
 </body>
</html>

XQuery je standardní dotazovací jazyk pro dotazy nad kolekcemi XML dat. Specifikace jeho verze 1.0 je rozšířením jazyka XPath verze 2.0. Pokud jste se s jazykem XQuery ještě nesetkali, dobrý tutoriál, jeho druhéa třetí pokračování najdete na serveru firmy Oracle. Omezení (a rozšíření) jeho implementace v databázi eXist najdete v její dokumentaci. Program funguje tak, že nejprve je zobrazen formulář (viz „běžný“ (X)HTML kód pod deklaracemi). Pak následuje „výkonná“ část XQuery, která buď zobrazí nápis „Řetězec nebyl zadán“, pokud parametr „sidlo“ nebyl zadán, nebo zkonstruuje XPath (například „ //sidlo[contains(.,'SLAVKOV')]“), dotáže se jím do databáze a vloží vrácený výsledek (posloupnost elementů) do dat generovaných v rouře.

Protože výše uvedený kód vkládá do čistého XHTML jakési „cizí“ elementy <sidlo>, je zapotřebí tyto prvky převést na požadované zobrazení pomocí primitivního stylesheetu hledej-psc.xsl .

Nyní se podívejme se na mapu aplikace:

<map:sitemap
xmlns:map="http://apache.org/cocoon/sitemap/1.0">

 <map:components>
  <map:generators default="file">
   <map:generator name="xquery"
        src="org.exist.cocoon.XQueryGenerator"/>
  </map:generators>
 </map:components>

  <map:pipelines>
    <map:pipeline>
      <map:match pattern="">
          <map:redirect-to uri="hledej-psc"/>
      </map:match>

    <map:match pattern="hledej-psc">
     <map:generate src="hledej-psc.xq"
                   type="xquery">
      <map:parameter name="use-request-parameters"
                     value="true"/>
    </map:generate>
    <map:transform src="hledej-psc.xsl"/>
    <map:serialize encoding="UTF-8" type="html"/>
   </map:match>

   <map:match pattern="db/**">
    <map:match type="request-parameter"
               pattern="xpath">
     <map:generate
          src="xmldb:exist:///db/{../1}#{1}"/>
     <map:serialize type="xml"/>
    </map:match>
    <map:generate src="xmldb:exist:///db/{1}"/>
    <map:serialize type="xml"/>
   </map:match>
 </map:pipeline>

 </map:pipelines>
</map:sitemap> 

Není zde asi nic, co by nás mohlo překvapit nebo s čím jsme se již dříve nesetkali. V úvodu je deklarován generátor XQuery, pokud v HTTP requestu požadujeme „hledej-psc“, vybere se zvýrazněná roura, která nejprve vygeneruje XHTML formulář, v případě vráceného výsledku s „cizími prvky“ <sidlo>. Ty se v dalším kroku XHTMLizují (to je ale slovo!) pomocí XSL transformace. Výsledek je pak serializován jako HTML a odeslán klientovi.

Na konci mapy je ještě jedna roura (pod tou výše uvedenou), která ukazuje použití pseudoprotokolu xmldb. Pokud v prohlížeči zadáte (bez uvozovek) URL například: „ http://localhost:8888/psc/db/ psc/psc.xml ?xpath=//sidlo[contains(.,'OPAV')]“ (pozn. ed.: obě mezery do URL přidány násilím kvůli sazbě –Johanka), vrátí se přímo XML prvky z databáze. Jako hodnotu parametru xpath můžete samozřejmě použít jakýkoliv korektní výraz XPath. Pokud v databázi vytvoříte další kolekce a (nebo) uložíte do ní další XML soubory, můžete v dotazech použít i je (nahraďte jimi zvýrazněnou část URL). Při pokusech doporučuji vždy omezit výsledek na nějakou rozumnou množinu, jinak můžete u prohlížeče čekat velmi dlouho, než se data zobrazí.

Další výhody XML databáze

XML databáze ve spolupráci s Cocoonem nabízejí mnohem více možností, než je možné v tomto článku nastínit. Nicméně bych se rád dotknul možnosti použít XML databázi jako centrální úložiště. Pseudoprotokol xmldb lze použít (skoro) všude, kde specifikujeme soubor. To znamená, že všechny XML soubory pro File generátor, stejně jako XSLT stylesheety pro XSLT transformátor (ale například i mapy) mohou být uloženy v XML databázi. To dává nový rozměr možnostem, jak lze zdrojové XML soubory a data strukturovat a co s nimi lze všechno dělat. Databáze eXist navíc umí ukládat i binární data, což se hodí, pokud je např. v databázi uložena dokumentace včetně obrázků. Zlepší se tak i škálovatelnost, protože databáze může běžet i na jiném stroji. Možnosti modifikace uložených dat mohou také hrát nezanedbatelnou roli, pokud budeme váhat, zda data uložíme jako soubory v systému, nebo v databázi.

Závěr

Nakonec bych chtěl upozornit na to, že zde výše uvedený příklad je opravdu primitivní a vlastně dost „špatně“ navržen (minimálně z hlediska Cocoonu). Určitě jste postřehli, že jsem si moc nelámal hlavu s oddělením obsahu a prezentace. V tomto konkrétním případě se směrovacími čísly by použití pseudoprotokolu xmldb s následnou transformací do (X)HTML (nebo jiného formátu) bylo asi lepším a „čistším“ řešením. Ale jak bych pak ukázal to XQuery? :-)

Také k mému „zabudování“ databáze eXist do zkompilovaného Cocoonu lze mít výhrady. Je to spíše „hack“ než metodický postup. Změny ve zdrojové části by však byly komplikovanější i pracnější a nelze je řešit prostým rozbalením archivu, což značně překračuje možnosti tohoto článku.

Cocoon a XML databáze jsou přirození spojenci. My jsme zde přidávali databázi eXist do Cocoonu, ale i naopak: plná instalace databáze eXisttaké obsahuje Cocoon (resp. jeho část). Na jejich stránkách se tak můžete podívat na další příklady s Cocoonem i bez něj.

Našli jste v článku chybu?

12. 3. 2004 13:04

Daniel M. Žák (neregistrovaný)

Rád bych Vám poděkoval za velmi hezký seriál o Cocoonu a pouze bych rád dodal následující:
XML Open Source databáze lze jenoduše nalézt na internetu, přičemž prozatím velmi dobře vypadá např. eXist, dále pak Berkeley DB XML (bohužel neobsahuje xUpdate). Trochu mě mrzí, že lidé od Apache se Xindice moc nevěnují, pořád nevím, zda projekt stagnuje či co. Nicméně společnost, která věnovala dbXML 1.0 Apache Group (to byl základ Xindice), uvolnila svoji verzi 2.0 do open source a je k dispozici na ad…

Podnikatel.cz: Změny v cestovních náhradách 2017

Změny v cestovních náhradách 2017

DigiZone.cz: Recenze Westworld: zavraždit a...

Recenze Westworld: zavraždit a...

120na80.cz: 5 nejčastějších mýtů o kondomech

5 nejčastějších mýtů o kondomech

Vitalia.cz: Paštiky plné masa ho zatím neuživí

Paštiky plné masa ho zatím neuživí

DigiZone.cz: TV Philips a Android verze 6.0

TV Philips a Android verze 6.0

Podnikatel.cz: Udávání kvůli EET začalo

Udávání kvůli EET začalo

Root.cz: Certifikáty zadarmo jsou horší než za peníze?

Certifikáty zadarmo jsou horší než za peníze?

120na80.cz: Na ucho teplý, nebo studený obklad?

Na ucho teplý, nebo studený obklad?

Vitalia.cz: Potvrzeno: Pobyt v lese je skvělý na imunitu

Potvrzeno: Pobyt v lese je skvělý na imunitu

Měšec.cz: Jak vymáhat výživné zadarmo?

Jak vymáhat výživné zadarmo?

120na80.cz: Co všechno ovlivňuje ženskou plodnost?

Co všechno ovlivňuje ženskou plodnost?

120na80.cz: Horní cesty dýchací. Zkuste fytofarmaka

Horní cesty dýchací. Zkuste fytofarmaka

Podnikatel.cz: Chtějte údaje k dani z nemovitostí do mailu

Chtějte údaje k dani z nemovitostí do mailu

Podnikatel.cz: Podnikatelům dorazí varování od BSA

Podnikatelům dorazí varování od BSA

Vitalia.cz: Mondelez stahuje rizikovou čokoládu Milka

Mondelez stahuje rizikovou čokoládu Milka

Podnikatel.cz: Snížení DPH na 15 % se netýká všech

Snížení DPH na 15 % se netýká všech

Vitalia.cz: Když přijdete o oko, přijdete na rok o řidičák

Když přijdete o oko, přijdete na rok o řidičák

Lupa.cz: Insolvenční řízení kvůli cookies? Vítejte v ČR

Insolvenční řízení kvůli cookies? Vítejte v ČR

DigiZone.cz: Rádio Šlágr má licenci pro digi vysílání

Rádio Šlágr má licenci pro digi vysílání

Vitalia.cz: Láska na vozíku: Přitažliví jsme pro tzv. pečovatelky

Láska na vozíku: Přitažliví jsme pro tzv. pečovatelky