XML - Verarbeitung mit Ant

Michael Günther, Vortrag im Seminar XML für Fortgeschrittene, Juni 2003


1. Vorstellung des Programms Ant


2. Anwendungsbeispiel: "Running Multiple XSLT Engines with Ant"


2. Anwendungsbeispiel: "XML Pipelining with Ant"


Was ist Ant

Geschichtsstunde


Entwickler: James Duncan Davidson
Entwicklungsgrund: Mangel an Funktionalität vorhandener Software
Entwicklungshintergrund: Plattformübergreifendes Softwareprojekt in 100% Java
Zeit: Mitte 1998
(his)story: Davidson musste seine Software auf drei verschiedenen Plattformen zum laufen bringen, um ihre 100% Pure Java Eigenschaft zu beweisen. Er wählte Solaris, Windows und MAC OS. Außerdem wollte er ebenso auf Linux arbeiten können. Um dies zu schaffen versuchte er GNU Make, dann shell Skripte, dann Batchdateien und nach eigener Aussage "God knows what else". Jede Variante hatte ihre eigene Problematik, schlußendlich lief alles zu langsam bzw. die Compilezeit war zu hoch. Schließlich versuchte er ein makefile zu schreiben, welches alle notwendigen Dateien in einem Schritt durch javac jagt. Erfolglos blieb jedoch die Portierbarkeit auf besagte drei Plattformen. Auf einem Flug von Europa nach USA entschied er sich ein eigenes Tool zu schreiben, dies war Ant. Der Rest war Mundpropaganda, er zeigte sein Tool eine Freund, der den Kollegen, die ihren Freunden ... . Und so begann die Anterfolgsstory.

Aufbau eines Ant-Programms


Das Antprogramm arbeitet mit einer nutzererstellten Arbeitsdatei.
Der Standardname ist build.xml.
Diese Datei wird in XML-Syntax geschrieben.

Aufbau einer build-Datei



Kopf

<?xml version="1.0"?>

allgemeine Programmstruktur

<project;>
  <target>
    <'taskname'>
    </'taskname'>
  </target>
</project>

Ein project umfasst ein oder mehrere targets, welche wiederum einen oder mehrere tasks umfassen kann.
Ein target ist ein Teilschritt des projects.
Ein task ist eine ausführbare Programmanweisung.

vollstandige Programmstruktur

<?xml version="1.0"?>

<project name="..." default="..." basedir="...">
  <target name="..." depends="..." description="..." if="..." unless="...">
    <'taskname' 'taskattribut'="..." ... >
    </'taskname'>
      ...
  </target>
   ...
</project>

Ein Projekt kann über das name-Attribut einen Namen zugewiesen bekommen, der allerdings nur für Dokumentationszwecke verwendet wird. Das default-Attribut enthält den Namen des targets mit dessen Abarbeitung Ant beginnen soll, wird dies nicht gesetzt beginnt Ant mit dem ersten target im Programm. Es sei an dieser Stelle erwähnt, dass sich beim Starten der build-Datei über entsprechende Parametereingabe ein oder mehrere targets gezielt aufrufen lassen. Hierfür werden die target-Namen verwendet. So lässt sich ein viel gößeres Antprogramm auch in einzelnen Teile ausführen. (Dies spiegelt die Grundidee eines Antprogrammes wieder einmal geschrieben zu werden, um vielfältigst Verwendung zu finden.) Mit dem basedir-Attribut wird das Stammverzeichniss der build-Datei angegeben. Ein Punkt, also basedir=".", bedeutet das sich die build-Datei im Ant-Verzeichniss befindet.

Ein target wird immer durch seinen Namen (name-Attribut) identifiziert, dies ist wichtig um Abhängigkeiten zwischen ihnen darstellen und ausführen zu können. Genau dies geschieht mit dem depends-Attribut. In ihm werden durch Komma getrennt die Namen der targets aufgeführt, welche vor dem momentanen target ausgeführt werden sollen. Die Reihenfolge der Auflistung ist ist hierbei von Bedeutung, allerdings lassen sich auch durch entsprechendes Setzen der depends-Attribute in den einzelnen targets schrittweise Abhängigkeiten schaffen. Das description-Attribut dient wiederum Dokumentationzwecken. if-Attribut und unless-Attribut sind Konditionsattribute die eine property referenzieren. Bei if muss sie gesetzt sein, damit das target ausgeführt wird, bei unless darf sie nicht gesetzt sein um das target auszuführen.

    property: Ist ein Datenelement in Ant. Es besteht aus einem Name-Wert-Paar von Stringdaten.
    <property name="..." value="..."/>
    Es kann auch eine externe property-Datei angegeben werden.
    <property file="..."/>

Ein task hat einen festgelegten Namen und wird auch über diesen aufgerufen. Weiterhin hat jeder task seine eigenen Attribute. In den Anwendungsbeispielen zum Thema werden einige tasks im Detail besprochen. Nachfolgend ist eine Liste der von Ant bereitgestellten tasks aufgeführt. Der erfahren Nutzer kann auch eigene tasks schreiben. Hier sei erwähnt das schon viele selbsterstellte tasks existieren, die noch nicht Fuß in Ant gefasst haben. Hierfür werden an späterer Stelle Beispiele gegeben.

tasks


Core Tasks

taskname antversion description
ant all Führt Ant auf einem anderen buildfile aus.
antcall all Ruft ein Target des momenteanen buildfiles auf.
antstructure all Erzeugt eine XML Document Type Definition (DTD) für Ant buildfiles.
apply 1.3, 1.4 Führt ein Systemkommando auf einem Datensatz aus.
available all Setzt eine property falls eine Resource verfügbar ist.
chmod all Ändert die Zugriffsrechte von Dateien und Verzeichnissen (nur für Unix).
condition 1.4 Setzt eine property falls eine Bedingung erfüllt wird.
copy all Kopiert Dateien und Verzeichnisse.
cvs all Führt Concurrent Versions System (CVS) Kommandos aus.
cvspass 1.4 Fügt ein Passwort zu einer .cvspass Datei hinzu, Äquivalent zu CVS login Kommando.
delete all Löscht Dateien und Verzeichnisse.
dependset 1.4 Verwaltet Abhängigkeiten zwischen Dateien, indem alle Zieldateien entfernt werden, falls eine nicht mehr aktuell ist in Bezug auf die Quelldateien.
ear 1.4 Baut Enterprise Application Archive (EAR) Dateien.
echo all Schreibt eine Nachricht in das Ant log oder eine Datei.
exec all Führt ein Native System Kommando aus.
fail all Wirft eine BuilException, die den laufenden build-Prozess stopt.
filter all Setzt einen Tokenfilter für das laufende Projekt.
fixcrlf all Räumt Spezialzeichen in der Quelldatei auf; tabs, carriage returns, linefeeds, EOF characters.
genkey all Generiert eine Schlüssel in einem "keystore".
get all Holt eine Datei von einer URL.
gunzip all Entpackt eine GZIPdatei.
gzip all Erzeugt eine GZIPdatei.
jar all Erzeugt eine JARdatei.
java all Führt eine javaKlasse aus.
javac all Kompiliert Javaquellcode.
javadoc all Startet das JavaDocWerkzeug um Quellcodedokumentation zu generieren.
mail all Sendet eine Email mit Hilfe von SMTP.
mkdir all Erstellt ein Verzeichnis.
move all Verschiebt Dateien und Verzeichnisse.
parallel 1.4 Führt multiple Tasks in laufenden Threads aus.
patch all Fügt eine "diff" Datei zum Original hinzu.
pathconvert 1.4 Konvertiert den Antpfad in einen plattformspezifizierten Pfad.
property all Setzt die properties im Projekt.
record 1.4 Dokumentiert den Output des laufenden Buildprozesses.
replace all Führt Stringersetzung in einem oder mehreren Dateien aus.
rmic all Startet den rmic Compiler.
sequential 1.4 Führt multiple Tasks sequentiell aus; zur Benutzung in Verbindung mit dem parallel Task.
signjar all Führt das javasign Kommandozeilentool aus.
sleep 1.4 Lässt den Buildprozess für ein festgelegtes Intervall pausieren.
sql all Führt SQLkommandos aus unter Benutzung von JDBC.
style/xslt all Führt XSLTtransformationen durch.
tar all Erzeugt ein TARarchiv.
taskdef all Fügt Nutzertasks zum laufenden Projekt hinzu.
touch all Aktualisiert den Zeitstempel von einer oder mehreren Dateien.
tstamp all Setzt die DSTAMP, TSTAMP und TODAY properties.
typedef 1.4 Fügt einen Datentyp zum laufenden Projekt hinzu.
unjar 1.3, 1.4 Entpackt ZIP-, WAR- oder JARdateien.
untar all Entpackt TARdateien.
unwar 1.3, 1.4 Entpackt ZIP-, WAR- oder JARdateien.
unzip 1.3, 1.4 Entpackt ZIP-, WAR- oder JARdateien.
uptodate all Setzt eine property falls eine oder mehrere Zieldateien aktuell sind in Bezug zu Ihren Quelldateien.
war all Erzeugt eine Web Application Archive (WAR) Datei.
zip all Erzeugt eine ZIPdatei.
Optional Tasks

antlr 1.3, 1.4 Startet den ANTLR Parser und das Übersetzungsgeneratorwerkzeug.
blgenclient 1.4 Erzeugt eine client JARdatei aus einer existierenden ejb-jar Datei.
cab all Erzeugt ein Microsoft .cab Archiv.
cccheckin 1.3, 1.4 Führt ein Rational ClerCase checkin Kommando aus.
cccheckout 1.3, 1.4 Führt ein ClearCase checkout Kommando aus.
ccmcheckin 1.4 Führt ein Continuus ci Kommando aus.
ccmcheckintask 1.4 Führt ein Continuus ci default-Kommando aus.
ccmcheckout 1.4 Führt ein Continuus co Kommando aus.
ccmcrestetask 1.4 Führt ein Continuus create_task Kommando aus.
ccmreconfigure 1.4 Führt ein Continuus reconfigure Kommando aus.
ccuncheckout 1.3, 1.4 Führt ein ClearCase uncheckout Kommando aus.
ccupdate 1.3, 1.4 Führt ein ClearCase update Kommando aus.
csc 1.3, 1.4 Kompiliert C# Quellcode.
ddcreator all Erzeugt serialized EJB deployment descriptors aus Textdateien.
depend 1.3, 1.4 Erklärt welche Klassendateien nicht aktuell sind, basierend auf einer Inhaltsanalyse zusätzlich zum Vergleich von Zeitstempeln der Klassendateien und Quelldateien.
ejbc all Führt BEA WebLogic Server's ejbc Toll aus um Code zu generieren, der zum Einfügen von EJB Komponenten in die Umgebung nötig ist.
ejbjar all Erzeugt ejb-jar Dateien kompatibel zu EJB 1.1.
ftp all Implementiert einen basic FTP client.
icontract 1.4 Führt den iContract Design By Contract Präprozessor aus.
ilasm 1.3, 1.4 Installiert .Net Intermediate Language Dateien.
iplanet-ejbc 1.4 Kompilert EJB stubs und skeletons für iPlanet Application Server Version 6.0.
javacc all Führt den JavaCC compiler compiler auf einer Grammatikdatei aus .
javah 1.3, 1.4 Führt das javah Tool aus, um Java Native Interface (JNI) headers von einer oder meheren Javaklassen zu generieren.
jdepend 1.4 Führt das JDepend Tool aus.
jjtree all Führt den JJTree Präprozessor für JavaCC aus.
jlink all Erzeugt eine JAR- oder ZIPdatei, optional mit Inhaltsverschmelzung von existierenden JAR oder ZIParchiven.
jpcoverage 1.4 Führt das JProbe Coverage Tool aus.
jpcovmerge 1.4 Fügt mehrere JProbe Coverage Schnapschüsse zu einem zusammen.
jpcovreport 1.4 Erzeugt einen Bericht über einen JProbe Coverage Schnapschuss.
junit all Führt einen Einheitentests unter Benutzung des JUnit testing framework aus.
junitreport 1.3, 1.4 Erzeugt einen formatierten Bericht über den junit task basierend auf mehreren XMLdateien.
maudit 1.4 Führt den WebGain Quality Analyzer aus um Java Quellcode auf Programmierfehler zu überprüfen.
mimemail 1.4 Sendet eine SMTP Mail mit MIME Anhang.
mmetrics 1.4 Führt den WebGain Quality Analyzer auf einem Satz von Javadateien aus und berichtet über Codekomplexität und andere Metriken.
mparse all Führt den now obsolete Metamata MParse compiler compiler auf einer Grammatikdatei aus.
native2ascii all Konvertiert Dateien mit native encoding in ASCII beinhaltende escaped Unicodezeichen.
netrexxc all Kompiliert eien Satz NetRexxdateien.
p4change 1.3, 1.4 Erfragt eine neue Änderungsliste von einem Perforce Server.
p4counter 1.4 Holt und setzt einen Perforce counter Wert.
p4edit 1.3, 1.4 Editiert Dateien von Perforce.
p4have 1.3, 1.4 Listet Perforcedateien von momentanen client view auf.
p4label 1.3, 1.4 Erzeugt ein label für Dateien im momentanen Perforce workspace.
p4reopen 1.4 VerschiebtDateien zwischen Perforce Änderungslisten.
p4revert 1.4 Findet geöffnete Perforce Dateien.
p4submit 1.3, 1.4 Meldet Dateien in einem Perfoce Depot an.
p4sync 1.3, 1.4 Synchronisiert einen workspace mit einem Perforce Depot.
propertyfile 1.3, 1.4 Erzeugt oder editiert Java property Dateien.
pvcs 1.4 Entpackt Dateien von einer PVCS Quelle.
rpm 1.4 Erzeugt eine Linux RPM Datei.
script all Führt ein BSFskript aus.
sound 1.3, 1.4 Spielt eine Sounddatei am Ende des Builprozesses ab.
starteam all Prüft Dateien von StarTeam.
stylebook 1.3, 1.4 Führt den Apache Stylebook Dokumentationsgenerator aus.
telnet 1.3, 1.4 Führt eine telnetsession aus.
test 1.3, 1.4 Führt einen Einheitstest im org.apache.testlet framework aus.
vsscheckin 1.4 Meldet Dateien bei Visual SourceSafe an.
vsscheckout 1.4 Meldet Dateien ab Visual SourceSafe ab.
vssget all Holt Dateien von Visual SourceSafe.
vsshistory 1.4 Zeigt die Geschichte von Dateien und Projekten in Visual SourceSafe.
vsslabel 1.3, 1.4 Bestimmt ein Label für Dateien und Projekte in Visual SourceSafe.
wljspc all Präkompiliert JSP Dateien mit BEA WebLogic Server's JSP compiler.
wlrun all Startet eine Instanz des WebLogic Server.
wlstop all Stopt eine Instanz des WebLogic Server.
xmlvalidate 1.4 Verifiziert die Wohlgeformtheit eines XML Dokumentes und validiert optional dieses mit dem SAX parser.

DataType


DataTypes sind ein weiteres Datenelement in Ant.
Sie umfassen:
datatype description
argument Ermöglicht es Kommandozeilenargumente für Programme einzugeben, die von Ant aufgerufen werden.
enviroment Spezifiziert Umgebungsvariablen für ein externes Kommando oder Programm, welches von Ant ausgeführt wird.
filelist Definiert eine Namensliste von Dateien, welche nicht unbedingt existieren müssen.
fileset Definiert eine Namensliste von Dateien, welche existieren müssen.
patternset Gruppiert einen Satz von Pattern
filterset Gruppiert einen Satz von Filtern
path Spezifizert einen Pfad in systemunabhängiger Form
mapper Definiert eine komplexe Beziehung zwischen einem Satz von Eingabedateien und einem Satz von Ausgabedateien


Anwendungsbeispiel 1: "Running Multiple XSLT Engines with Ant"


original site
Die Idee ist mit Hilfe von Ant ein Programm zu schreiben, das XML-Dateien automatisiert über XSLT-Transformation in gültiges HTML zu überführt. Schritt zwei ist zusätzlich die Einbindung verschiedener XSLT-Engines in den Prozess. Ziel ist es mit einem Programmaufruf, in diesem Fall der Ant-build-Datei, alle benötigten XML-Dateien mit Hilfe aller gewünschter XSLT-Engines in die gewollten HTML-Dateien zu überführen.

Zuerst die einfachste Variante: 1 Inputdatei, 1 XSLT-Engine, 1 Outputdatei

<project default="do-it">  
  <target name="do-it">    
    <xslt processor="trax" in="input.xml" style="transform.xsl "out="output.html"/>
  </target>
</project>

xslt ist der Taskname, das processor-Attribut spezifiziert die XSLT-Engine, das in-Attribut die Inputdatei, das style-Attribut die Transformationdatei (stylesheet) und das out-Attribut die Ausgabedatei.

Zur Zeit werden mit 'trax' alle zu Sun's JAXP 1.1 kompatiblen Prozessoren unterstützt und mit 'xalan' wird Apache Xalan v1.x unterstützt.

xslt verfügt weiterhin über folgende Attribute:
basedir Spezifiziert wo die XML-Dateien zu finden sind. Der default-Wert ist die basedir des project.
classpath Der Klassenpfad, der beim XSLT-processor Verwendung findet.
classpathref Eine Referenz auf einen Klassenpfad der irgenwosonst in der build-Datei spezifiziert ist
defaultexcludes boolean-Variable, die bestimmt, ob defaultexcludes (Standardausnahmen, d.h. vor Veränderung zu schützende Dateien) benutzt werden sollen. der default-Wert ist true. Zu den defaultexcludes gehören: **/*~, **/#*#, **/.#*, **/%*%, **/CVS, **/CVS/**,**/.cvsignore, **/SCCS, **/SCCS/** und **/vssver.scc.
destdir Spezifiziert das Verzeichnis wo die Ergebnisse der Transformation gespeichert werden sollen. ist erforderlich falls das in- und out-Attribut nicht verwendet wird.
excludes Eine durch Komma getrennte Liste von Dateipattern die ausgeschlossen werden sollen. Diese sind zuzüglich zu den defaultexcludes.
excludesfile Definiert eine Datei, welche einen exclude pattern pro Zeile enthält
extension Definiert die default Dateiendung für die Ergebnisse der Transformation. default ist .html
force boolean-Variable die bewirkt, dass die Zieldateien auch erzeugt werden, wenn ihre Quell-XML-Dateien oder XSLT-Dateinen neuer sind. default-Wert ist false.
in Spezifizert eine einzelne XML-Datei. Muss zusammen mit dem out-Attribut verwendet werden.
includes Eine durch Kommas getrennte Liste von Dateipattern, die eingeschlossen werden sollen.
includesfile Definiert eine Datei, welche einen include pattern pro Zeile enthält
out Spezifizert einen einzelnen Dateinamen. Muss zusammen mit dem in-Attribut verwendet werden.
processor Der zu benutzende XSLT-Prozessor
style Der XSLT-stylesheet-Name.

Jetzt eine komplexere Variante:

Workflow-Diagramm
Es sollen drei verschiedene XML-Dateien in einer HTML-Datei zusammengefasst werden. Zuerst wird jede einzelne der XML-Dateien normalisiert, d.h. sie wird mit Hilfe eines speziellen Stylesheet mit den anderen XML-Dateien in eine einheitliche Form gebracht. Nun können mit Hilfe eines weiteren Stylesheets  die normalisierten XML-Dateien zusammengefügt werden. Auf Grund der Eigenschaften ieses Stylsheets muss dies in zwei Schritten geschehen. Schlußendlich kann dann die Zusammengefügte XML-Datei in die gewünschte Ausgabedatei transformiert werden.

Ein realer Bezugspunkt ist die Vorstellung von drei getrennt von einander arbeitenden Nutzern, wobei jeder nur einen Teil eines Großprojektes bearbeitet. Ihr Chef könnte mit dem obigen Programm und den jeweiligen Teilstücken sich das fertige Gesamtprojekt betrachten.

<project default="sort">

  <target name="normalize">
    step1
    <xslt processor="trax" in="in1.xml" style="norm1.xsl" out="nm1.xml"/>
    step2
    <xslt processor="trax"in="in2.xml"style="norm2.xsl"out="nm2.xml"/>
    step3
    <xslt processor="trax"in="in3.xml"style="norm3.xsl"out="nm3.xml"/>
  </target>

  <target name="check12">
    <uptodate property="skip.merge12"targetfile="m12.xml">
      <srcfiles dir=".">
        <include name="nm1.xml"/>
        <include name="nm2.xml"/>
        <include name="merge.xsl"/>
      </srcfiles>
    </uptodate>
  </target>

merge12
  <target name="merge12"depends="normalize,check12"unless="skip.merge12">
    <xslt processor="trax"in="nm1.xml"style="merge.xsl"out="m12.xml"force="true">
      <param name="source2"expression="nm2.xml"/>
    </xslt>
  </target>
 
  <target name="check123">
    <uptodate property="skip.merge123"targetfile="123.xml">
      <srcfiles dir=".">
        <include name="m12.xml"/>
        <include name="nm3.xml"/>
        <include name="merge.xsl"/>
      </srcfiles>
    </uptodate>
  </target>
  merge123
   <target name="merge123"depends="normalize,merge12,check123"unless="skip.merge123">
    <xslt processor="trax"in="m12.xml"style="merge.xsl"out="123.xml"force="true">
      <param name="source2"expression="nm3.xml"/>
    </xslt>
  </target>
  sort
  <target name="sort"depends="merge123">
    <xslt processor="trax"in="123.xml"style="sort.xsl"out="out.xml"/>
  </target>

  <target name="clean">
    <delete>
      <fileset dir=".">
        <include name="output.html"/>
        <include name="nm*.xml"/>
        <include name="m12.xml"/>
        <include name="123.xml"/>
        <include name="out.xml"/>
      </fileset>
    </delete>
  </target>

</project>

Die targets check12 und check123 prüfen ob die unter include aufgeführten Dateien aktueller (, d.h. einen aktuelleren Zeitstempel haben) sind, als die unter targetfile bezeichnete Datei. Ist dem nicht so verhindert das die Zieldatei (targetfile) verändert wird. Sollte dies trotzdem gewünscht sein, ruft man die targets merge12 oder merge123 eben gesondert auf, da sie das force-Attribut enthalten wird der Aktualität keine Beachtung mehr geschenkt. (Bei normalen startendes Programms würden sie Übergangen werden bevor das force-Attribut Wirkung zeigen könnte.)

Das clean target ist zum Aufrämen gedacht und löscht einfach die hier verwendeten Dateien.

Weitere Neuheiten sind :
<srcfiles>   Spezifizert einen Satz Quelldateien.  Im Beispiel die Quelldateien der target-Datei des uptodate-tasks.
  <include>   Spezifiziert eine einzelne Datei. Wichtig hierbei ist, dass include wildcards unterstützt.(D.h. *.xml, nx*.xml, md.*, n*m*.*h, etc. .)
<param>   Spezifizert einen Parameter der Übergeben wird.  Im Beispiel die zweite Quelldatei für das merge-Stylesheet.
<fileset>    Spezifiziert einen Satz von Dateien.  Im Beispiel den Satz zu löschender Dateien im delete-task.

In der nächsten Varianten werden nun außer dem 'trax'-Prozessor auch andere XSLT-Prozessoren (XSLT-Engines) verwendet.
Hierfür findet der mtxslt-task Verwendung. mtxslt gehört nicht zu den Antstandardtasks. Er erweitert den vorhandenen xslt-task und ist ein Beispieleiens user-written-task. Er ermöglicht es folgente XSLT-Engines zu verwenden: Xalan 2, Saxon 6/7 und  Oracle XDK 9


<project name="test"default="all">

  <taskdef name="mtxslt"classname="org.xmLP.ant.taskdefs.xslt.XSLTProcess"/>

  <property name="trax"value="org.xmLP.ant.taskdefs.optional.TraXLiaison"/>
  <property name="xalan2"value="org.xmLP.ant.taskdefs.optional.Xalan2Liaison"/>
  <property name="xalan2.classpath"value="D:\home\tony\XSLT\xalan-j_2_4_0\bin\xalan.jar"/>
  <property name="saxon6"value="org.xmLP.ant.taskdefs.optional.Saxon6Liaison"/>
  <property name="saxon6.classpath"value="D:\home\tony\XSLT\Saxon-6.5.2\saxon.jar"/>
  <property name="saxon7"value="org.xmLP.ant.taskdefs.optional.Saxon7Liaison"/>
  <property name="saxon7.classpath"value="D:\home\tony\XSLT\Saxon-7.1\saxon7.jar"/>
  <property name="oracle9"value="org.xmLP.ant.taskdefs.optional.Oracle9Liaison"/>
  <property name="oracle9.classpath"value="D:\home\tony\XSLT\xdk_java_9_2_0_3_0\lib\xmlparserv2.jar"/>

  <target name="all"depends="trax1,trax2,trax3,trax4,xalan2,saxon6,saxon7,oracle9"/>

  <target name="trax1">
    <xslt processor="trax"in="input.xml"style="transform.xsl"out="trax1.html">
      <param name="target"expression="trax1"/>
    </xslt>
  </target>

  <target name="trax2">
    <mtxslt processor="trax"in="input.xml"style="transform.xsl"out="trax2.html">
      <param name="target"expression="trax2"/>
    </mtxslt>
  </target>

  <target name="trax3">
    <xslt processor="${trax}"in="input.xml"style="transform.xsl"out="trax3.html">
      <param name="target"expression="trax3"/>
    </xslt>
  </target>

  <target name="trax4">
    <mtxslt processor="${trax}"in="input.xml"style="transform.xsl"out="trax4.html">
      <param name="target"expression="trax4"/>
    </mtxslt>
  </target>

  <target name="xalan2">
    <mtxslt processor="${xalan2}"in="input.xml"style="transform.xsl"out="xalan2.html"classpath="${xalan2.classpath}">
      <param name="target"expression="xalan2"/>
    </mtxslt>
  </target>

  <target name="saxon6">
    <mtxslt processor="${saxon6}"in="input.xml"style="transform.xsl"out="saxon6.html"classpath="${saxon6.classpath}">
      <param name="target"expression="saxon6"/>
    </mtxslt>
  </target>

  <target name="saxon7">
    <mtxslt processor="${saxon7}"in="input.xml"style="transform.xsl"out="saxon7.html" classpath="${saxon7.classpath}">
      <param name="target"expression="saxon7"/>
    </mtxslt>
  </target>

  <target name="oracle9">
    <mtxslt processor="${oracle9}"in="input.xml"style="transform.xsl"out="oracle9.html"classpath="${oracle9.classpath}">
      <param name="target"expression="oracle9"/>
    </mtxslt>
  </target>

  <target name="clean">
    <delete>
      <fileset dir="."includes="*.html"/>
    </delete>
  </target>

</project> Was neu ist:

<taskdef> Definiert einen selbsterstellten task.
Die Verwendung von properties zur Referenzierung von Klassennamen und Quelldateistandorten. Dies ist vollkommen unproblematisch, da eine property wertungsfrei mit den in ihr angegebenen Werten umgeht. Sie werden einzig und allein als String behandelt (, ein String der als Wert einem anderen String, der Variablen, zugeordnet wird).

Zur Funktion der targets:

all führt alle anderen targets aus, ausser clean.
trax1 benutzt den Standard-xslt-task.
trax2 benutzt den mtxslt-task um das gleiche wie trax1 zu tun.
trax3 ist wie trax1 nur das im processor-Attribut eine Variable trax in der Form &{trax} angesprochen wird, deren Wert über die entspechende property zugewiesen ist. (In diesem Fall genau die Klasse auf die auch die normale trax-Variable verweist.)
trax4 ist wie trax3 nur unter Verwendung von mtxslt.
xalan2, saxon6, saxon7, oracle9 benutzen jeweils mtxslt, wobei die in trax3/4 verwendet Variablenzuweisung die jeweilige XSLT-Engine referenziert. Wichtig ist hierbei die angabe der classpath-Variablen, damit Ant auch die zugehörigen Dateien findet.

Auf diese Weise lassen sich mehr XSLT-Engines verwenden, weiterhin stellt das all-target mit dem depends-Attribut eine einfache Lösung dar um alle gewünschten Engines auf eine (oder mehrere) Quelldatei(en) anzuwenden

Anwendungsbeispiel 2: "XML Pipelining with Ant"


original site

In diesem Beispiel wollen wir die Idee mit einem Antprogramm mehrere auch verteilte Arbeitsvorgänge in einem zusammenzufassen weiter vorantreiben.
Das Anwendungsbeispiel bezieht sich hierbei auf die Validierung von XML-Dokumenten.
XML-Dokumente werden gemäß einer gegebenen DTD auf Korrektheit überprüft. Ant hat hierfür seine eigene DTD parat, welche sich im Quellcode versteckt.
Wer genaueres über sie erfahren will, kann sie mit folgenden Zauberworten herauslocken.

<?xml version="1.0"?>

<project default="dtd">
  <target name="dtd">
    <antstructure output="ant.dtd"/>
  </target>
</project>


Jetzt wo die Spezifikationen für die Überprüfung klar sind, lässt sich mit Hilfe des xmlvalidate-task jedes XML-Dokument überprüfen.

<?xml version="1.0"?>

<project default="valid">
  <target name="valid">
    <xmlvalidate file="date.xml"/>
   </target>
</project>
       
[um mehrere Dateien anzugeben, verfährt man wie folgt:
              <xmlvalidate>
                <fileset file="date*.xml"/>
              </xmlvalidate>
]



 Der xmlvalidate-task verfügt über die Attribute:

classname
Enthält den Javaklassennamen des SAX-Parsers der benutzt werden soll.
classpath
Der Klassenpfad der verwendet wird.
classpathref
Eine Referenz auf einen irgendwosonst in der build-Datei definierten Klassenpfad.
failonerror
Eine boolean-Variable, die den build-Prozess abricht,falls sie true ist. default ist true.
file
Gibt die zu überprüfende XML-Datei an. Kann auch ein <fileset> enthalten, welches mehrere XML-Dateien spezifiziert
lenient
boolean-Variable, die, falls true, angibt das ein XML-Dokument zwar wohlgeformt, aber nicht validierbar ist. Funktioniert nur mit einem SAX2-Parser. default ist false.
warn
boolean-Variable, welche, wenn true, Warnungen in eine log-Datei schreibt. default ist false.

Da dies nur eine Sicht der Überprüfbarkeit von XML-Dokumenten ist, wurden zusätzlich task geschrieben.
Einer davon ist der jing-task, welcher es ermöglicht RELAX NG Schemata zur Validierung heranzuziehen.

<?xml version="1.0"?>

<project default="rng">

  <taskdef name="jing" classname="com.thaiopensource.relaxng.util.JingTask"/>

  <target name="rng">
    <echo message="Validating RELAX NG schema with Jing..."/>
    <jing rngfile="date.rng" file="date.xml"/>
  </target>

</project>

Das RELAX NG Schemata muss in einer Datei mit der Endung .rng  gespeichert sein und wird über das rngfile-Attribut des jing-tasks aufgerufen.

Der echo-task ermöglicht die Ausgabe von Textmitteilungen auf die Kommandozeile, während des build-Prozesses.

jing bietet weiterhin auch die Validierung gegen RELAX NG Schemata in compact syntax an.
Hierfür wird der Aufruf von jing geändert:

<jing compactsyntax="true" rngfile="date.rnc" file="date.xml"/>

Zu beachten ist das die Endung der das schemaenthaltenen Datei in .rnc wandelt.

Damit haben wir das nötige Wissen um XML-Dokumente zu validieren.
Was heißt jetzt XML pipelining?
Die Idee ist wieder Automatisierung einzelner Arbeitschritte durch Aufrufen eines Antprogramms.

Ein einfaches Beispiel: Mr. Projektleiter soll jeden Freitag prüfen, ob die XML-Dokumente die seine Mitarbeiter überall auf der Welt erstellt haben auch korrekt sind und somit auf den Rechnern im Firmenhauptsitz richtig angezeigt werden können. Hierfür hat er folgendes Antprogramm geschrieben.

<?xml version="1.0"?>

<project default="mail">

  <taskdef name="jing" classname="com.thaiopensource.relaxng.util.JingTask"/>

  <target name="init">
    <echo message="Load XML properties..."/>
    <xmlproperty file="properties.xml"/>
  </target>

  <target name="get" depends="init">
    <get src="http://www.wyeast.net/date.zip" dest="date.zip"/>
  </target>

  <target name="unzip" depends="get">
    <unzip src="date.zip" dest="${build.dir}"/>
  </target>

  <target name="rng" depends="unzip">
    <echo message="Jing validating..."/>
    <jing rngfile="date.rng" file="date.xml"/>
  </target>

  <target name="val" depends="rng">
    <xmlvalidate file="date.xml">
      <xmlcatalog>
        <dtd publicId="-//Wy'east Communications//Date DTD//EN"location="date.dtd"/>
      </xmlcatalog>
    </xmlvalidate>
  </target>

  <target name="xform" depends="val">
    <xslt in="date.xml" out="date.html" style="date.xsl">
      <outputproperty name="method" value="xml"/>
      <outputproperty name="indent" value="yes"/>
    </xslt>
  </target>

  <target name="mail" depends="xform">
    <mail mailhost="mail.example.com" subject="Ant build">
      <to address="schlomo@example.com"/>
      <from address="hermes@example.com"/>
      <message>Complete!</message>
    </mail>
  </target>

</project>

Das default-target ist mail. Über die Abhängikeiten in den depends-Attributen gelanngen wir zum init-target welches im xmlproperty-task eine XML-Datei liest welche  die benötigten properties  enthält.
Hier sieht dieses  so aus:

<?xml version="1.0"?>

  <build>
    <dir>.</dir>
  </build>

Dies heißt nichts weiter als ${build.dir} enthält '.' (Punkt).
get holt eine ZIP-Datei von der angegebenen Adresse.
unzip entpackt diese.
rng validiert das enthaltene XML-Dokument gemäß der lokalen Schemata-Datei.
val validiert nochmals, diesmal jedoch gemäß einer DTD.
xform führt die XSLT-Transformation durch.
Und schließlich sendet mail eine Bestätigungs-E-mail.


Mit dieser Idee im Hinterkopf lassen sich auch komplexere Pipelines erstellen.

Viel Spaß dabei.