20 července 2009

XSLT a zpracování několika transformacemi

Při používání XSLT jsem narazil na problematiku zpracování jednoho dokumentu několika následnými XSLT transformacemi. Možná se Vám stalo (podobně jako mě), že předchozí transformace upravila dokument a odstranila některé tagy, které chceme v další transformaci zpracovat (poznámka autora: neobjevuji tu kolo, jen poukazuji na možné řešení).

Příklad (pouze obsah xml dokumentu)
<tagProZpracovani_DRUHOU_Transformac>
<tagProZpracováni_PRVNI_transformaci />
</tagProZpracováni_DRUHOU_transformaci>


Pokud bychom použil transformaci T1, a ve které bychm zpracovali pouze vnitřní tag, vnější tagy by byli odstraněny.

Celý "problém" řeší následující XSLT - neboli transformace T1.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>

<xsl:template match="tagProZpracováni_PRVNI_transformaci" >
<!-- tělo transformace -->
</xsl:template>
</xsl:stylesheet>


Pokud si neumíte představit kdy něco takového použít, vydržte, popíšu v příštím článku jak ulehčit práci při psaní DocBooku. Třeba tím, že si vygenerujeme vlastním tagem obsah tabulky - tzn. první transformací (T1) si vytvoříme validní dokument a druhou (T2) přeložené html. :)

17 července 2009

XSLT a spouštění Java procedur (se Saxonem)

XSLT transformace - mocný nástroj, avšak čas od času se potýkám s nějakou nejasností, která komplikuje práci. Jak spouštět vlastní java kód (který provede konkrétní výpočet, něco vytáhne z databáze apod. ) na internetu naleznete mraky. Co mě ale dělalo problém - rozchodit celý proces z příkazové řádky. Pojďme se tedy na to podívat. V popisu předpokládám základní znalost XSLT a Javy.

Co budeme potřebovat:
  • Saxon 6.5 (pro XSLT 1.0) nebo Saxon 9.1 (pro XSLT 2.0) třeba z http://saxon.sourceforge.net
  • vlastní xml soubor, který chceme překládat
  • transformace, kterou budeme překládat xml soubor
  • chceme zavolat java metodu, tak java třídu

Vytvoříme si adresářovou strukturu:
/
Src - kde budou zdrojový soubory
Tools - kde budou nástroje
|
|-- preprocessors - balík s java třídami
|-- xslt - kde budou transfomace
|-- saxon_6.5.5 - kde bude saxon


Vytvoříme si java třídu a transformaci. Předpokládejme, že v třídě je statická metoda, která se jmenuje getNum() - vrátí nám nějaké číslo, třeba číslo 2 (třídu si před použitím musíme přeložit, tak aby na daném místě byl class soubor).

Zdrojový soubor xml:
<?xml version="1.0" encoding="UTF-8"?>
<mutag>
<javatag />
</mutag>


Transformace bude vypadat následovně:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:proc="preprocessors.TestClass"
exclude-result-prefixes="proc"
>
<xsl:template match="javatag">
<para><xsl:value-of select="proc:getNum()" /></para>
</xsl:template>
</xsl:stylesheet>


Za zmínku stojí xmlns:proc - kde se odkazujeme na daný balík s danou třídou (místo prefixu proc můžete použít cokoli třeba oblíbené foo :-)). A následně samotné zavolání funkce .

A teď to vše uvedeme do chodu. Uďěláme si dávkový soubor - "baťák".
@echo off
SET CLASSPATH=.\saxon_6.5.5\saxon.jar;.
REM SET CLASSPATH=.\saxon_9.1\saxon9.jar;.

REM saxon v6.5.5
@java com.icl.saxon.StyleSheet -o javaCallResult.xml ..\Src\javaCall.xml xslt\preprocessor.xsl

REM saxon v9.1
REM @java net.sf.saxon.Transform -o javaResult.xml ..\Src\javaCall.xml xslt\preprocessor.xsl
@echo on


Povšiměte si voláme Saxon ne přes Jar soubor, ale přes třídu. Přes jar soubor se mi to nepodařilo zprovoznit (v dávkovém souboru vidíte zakomentovaný příklad i pro Saxon 9.1).

Výsledkem je tedy javaCallResult.xml soubor který obsahuje pouze 2.

Pokud by Vám příklad nefungoval stahněte si celou ukázku.

Spoluautorem ukázky je Martin Augusta, kterému děkuju za spolupráci.