Hlavní navigace

Cocoon v příkladech: Programujeme vlastní komponenty 2

23. 6. 2004
Doba čtení: 4 minuty

Sdílet

V posledním dílu tohoto seriálu si ukážeme, jak naprogramovat trošičku složitější komponentu - transformátor.

Opakování

Transformátor je jedním ze základních typů komponent, na kterých je Cocoon postaven. Na vstupu přijímá XML data ve formě proudu událostí SAX. XML data jsou nějak transformována a transformátor posílá na výstup opět proud událostí SAX, které dostává na vstup další komponenta v rouře. Transformátor patří k těm složitějším komponentám, i když složitost v kontextu Cocoonu nemusí odpovídat tomu, co si pod pojmem „složitý program“ představuje průměrný vývojář nebo návrhář. Pro úspěšné naprogramování transformátoru je potřeba alespoň něco vědět o XML, mít představu, jak se používá rozhraní SAX (nebo alespoň DOM) a něco málo tušit o životním cyklu komponent v systému Avalon, na kterém je Cocoon založen. Nicméně naprogramovat primitivní transformátorek není zase tak obtížné.

Zadání

Naprogramujeme transformátor, který bude transformovat prvek <kokos> z jmenného prostoru „ http://psykora.net/cocoon/trafo/1.0“ na prvek <losos>, který bude obsahovat text „bla bla“ (plus případný další obsah prvku). Jiné elementy z výše uvedeného jmenného prostoru budou vypuštěny. Jinými slovy, budeme-li mít např. tato XML data na vstupu našeho transformátoru:

<a xmlns:t="http://psykora.net/cocoon/trafo/1.0">
  <b>
    <t:kokos/>
  </b>
  <t:kokos>text</t:kokos>
  <t:cosi>aaa</t:cosi>

</a>

měli bychom na jeho výstupu dostat toto:

<a>
  <b>
    <losos>bla bla</losos>

  </b>
  <losos>bla blatext</losos>
  aaa
</a>

Realizace

Zdrojový kód transformátorů z Cocoonu lze najít v adresáři „ src/java/org/apache/cocoon/transformation“. Abychom neměli problémy s překladem a spuštěním, přidáme do výše zmíněného adresáře také náš transformátor (samozřejmě v případě normálního projektu by bylo asi lepší mít vlastní strukturu adresářů oddělenou od Cocoonu). Náš transformátor bude implementovat třída MojeTrafo

package org.apache.cocoon.transformation;

import org.apache.cocoon.ProcessingException;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import java.io.IOException;

public class MojeTrafo
    extends AbstractSAXTransformer {

  public static final String
      MOJE_URI =
      "http://psykora.net/cocoon/trafo/1.0";

  public static final
      String SOURCE_ELEMENT = "kokos";

  public static final
      String TRANSFORMED_ELEMENT = "losos";

  public MojeTrafo() {
    this.namespaceURI = MOJE_URI;
  }

  public void startTransformingElement(
      String uri, String name,
      String raw, Attributes attr)
    throws
      ProcessingException,
      IOException,
      SAXException
  {
    if (name.equals(SOURCE_ELEMENT)) {
      sendStartElementEvent(TRANSFORMED_ELEMENT);
      sendTextEvent("bla bla");
    }
  }

  public void endTransformingElement(
      String uri, String name, String raw)
    throws
      ProcessingException,
      IOException,
      SAXException
  {
    if (name.equals(SOURCE_ELEMENT)) {
      sendEndElementEvent(TRANSFORMED_ELEMENT);
    }
  }

}
MojeTrafo 
  1. Určit jmenný prostor pro naše zdrojové prvky (např. v konstruktoru)
  2. Implementovat metodu startTransformingElement, která popíše reakci transformátoru na SAX událost začátku prvku z určeného jmenného prostoru (např. můžeme vygenerovat událost začátek transformované­ho prvku)
  3. Implementovat metodu endTransformingElement, která popíše reakci transformátoru na SAX událost konce prvku z určeného jmenného prostoru (např. můžeme vygenerovat událost konec transformovaného prvku).

„Logika“ našeho transformátoru je triviální, v normálních případech bude potřeba dostat a zpracovat další informace (konfigurace, HTTP požadavek, parametry, logování …). Třída AbstractSAXTran­sformer toho pro nás „předžvýká“ poměrně dost, nicméně bude obvykle nutné implementovat i další metody. Rozhodně doporučuji podívat se na zdrojový kód nějakého jiného transformátoru, který je potomkem třídy AbstractSAXTran­sformer (např. CIncludeTransformer) i na kód třídy samotné.

Použití

Po překladu (resp. v našem případě je potřeba „rebuildovat“ Cocoon a restarovat jej, pokud běžel) můžeme vytvořit webovou „aplikaci“ s názvem „trafo“ např. s touto mapou:

<?xml version="1.0"?>

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

  <map:components>
    <map:transformers default="xslt">

      <map:transformer name="trafo"
src="org.apache.cocoon.transformation.MojeTrafo"/>
    </map:transformers>
  </map:components>

  <map:pipelines>
    <map:pipeline>

      <map:match pattern="">
        <map:generate src="pokus.xml"/>
        <map:transform type="trafo"/>
        <map:serialize type="xml"/>
      </map:match>

    </map:pipeline>

  </map:pipelines>

</map:sitemap>

Všechny potřebné soubory najdete v archivu, takže zbývá jen rozbalit, rebuildovat Cocoon a spustit aplikaci ( http://localhost:8888/trafo/).

CS24_early

Možné problémy

Při tvorbě transformátorů je potřeba vzít v úvahu následující potenciální problém: Pokud dojde k chybě uvnitř transformátoru, která vyvolá výjimku, může lehce dojít k vytvoření dat, která nesplňují ani základní pravidla XML (tj. nejsou „well-formed“). Další komponenty v rouře se pak s takovými daty nemusejí vypořádat. Při ošetřování výjimek je vždy dobré se zamyslet, zda generovaná XML data jsou i v těchto případech v pořádku.

Závěr

Rád bych poděkoval laskavým čtenářům, kteří se prokousali seriálem až sem. Pokud jste měli někdy pocit, že Cocoon je složitý a že byste v něm nejraději nic nedělali, není to chyba Cocoonu, ale moje, že jsem to nedokázal dostatečně přístupně popsat. Máte-li pocit, že Cocoonu ještě něco chybí, aby vám stálo za to jej zvážit jeho použití pro vaši webovou aplikaci, podívejte se na něj podrobněji. Tento seriál nepopsal zdaleka vše, co je v Cocoonu obsaženo a co je v něm možné udělat.

Byl pro vás článek přínosný?