Werbung einblenden Werbung ausblenden


Home / Tutorials / xml, xsl, xpath Handbuch / xslt


Auslesen eines XML-Dokumentes mit XSLT
Aufbau eines XSLT-Stylesheet
Die Funktion template match
Zugriff auf einen bestimmten Knoten aus einer Gruppe gleichnamiger Knoten
Transformation in ein HTML-Dokument
Das Ergebnis der Transformation, den Ergebnisbaum, direkt im Browser zeigen
Ermitteln des Wertes eines Attributes
Mehrere Attribute eines Knotens anzeigen lassen
Aufsummieren der Werte eines Attributes
Auslesen aller gleichnamigen Knoten in unterschiedlichen Gruppen
Navigieren mit Hilfe von Achsen
Die Achse following-sibling
Die Achse preceding
Ein XML-Dokument mit XSLT modifizieren
Ein Element hinzufügen
Ändern eines Elementes
Löschen eines Elementes
Ein Element innerhalb des Dokumentes umpflanzen
Elemente sortieren mit XSLT
Datensätze nummerieren
Bedingte Anweisungen xsl:if und xsl:choose
Eine Bedingung von mehreren ist richtig: xsl:choose
Funktionen zum Arbeiten mit Zeichenketten
Die Funktion string-length
Die Funktion concat
Die Funktion contains
Die Funktion start-with
Die Funktion substring
Die Funktionen substring-before und substring-after
Anzahl der Knoten ermitteln
Den letzten Knoten ermitteln
X-beliebigen Knoten ermitteln
Auf gleichnamige Elemente zugreifen, die in unterschiedlichen Knoten sind

Auslesen eines XML-Dokumentes mit XSLT

XSLT (Extensible Stylesheet Language Transformation) ermöglicht es, ein XML-Dokument zu transformieren, z.B. in ein HTML-Dokument. Allerdings ist dies nicht der einzige Ansatz. In dem Moment, in dem es gelingt, den Inhalt eines Knotens, Text oder Attribute auszulesen, ist es möglich, diesen Inhalt in HTML einzuwickeln. Man kann also auch mit der DOM Spezifikation oder mit XPATH, siehe Auslesen einer XML-Datei mit dem Perl Modul XML::LIBXML und DomXML und PHP eine XML-Datei transformieren. Aus didaktischen Gründen wünschen wir uns eine Möglichkeit, diese Transformation von der Kommandoebene (Dos Box, Eingabeaufforderung) durchzuführen. Deshalb benötigen wir eine Software, die dies ermöglicht. Am einfachsten geht das mit SAXON, den wir uns hier downloaden können. Saxon ist ein C-Programm, dass beim Aufruf zwei Paramater übergeben bekommt, die XML-Datei und das Stylesheet und das dann die Transformation durchführt. Optional ist ein dritter Parameter, wenn wir die transformierte Datei auf der Festplatte speichern wollen. Alle folgenden Beispiele gehen von der unten stehenden XML-Datei aus. Auf XPATH, sozusagen das sql von XSLT, wird nur insoweit eingegangen, als es nötig ist, um das Zusammenspiel mit XSLT zu verstehen. Für eine detaillierte Darstellung von XPATH siehe Abfragen mit XPATH.

<?xml version="1.0" encoding="ISO-8859-1"?>
<Projekte>
<Gruppe>
<Gruppenname stand="abgeschifft">Berliner Verwaltungsreform</Gruppenname>
<Kollegen>
<Mitarbeiter Firma="Preis Wasserhaus">Werner Lepinski</Mitarbeiter>
<Mitarbeiter>Erika Saufwech</Mitarbeiter>
<Mitarbeiter>Hans Geldfliech</Mitarbeiter>
</Kollegen>
<Ansprechpartner Telefon="030-435555" Ident="A_1">Otto Moltoimportante</Ansprechpartner>
<Adresse>
<Strasse Gegend="teures Pflaster">Kurfürstendamm 5</Strasse>
<Ort>13453 Berlin</Ort>
</Adresse>
<Budget>40 000000</Budget>
<Kommentar>Alles wird gut</Kommentar>
</Gruppe>
<Gruppe>
<Gruppenname>Hamburger Verwaltungschaos </Gruppenname>
<Kollegen>
<Mitarbeiter Firma="Arthur der Kleine">Werner Nordflut</Mitarbeiter>
<Mitarbeiter>Marina Meimportauncarajo</Mitarbeiter>
<Mitarbeiter>Peter Wessnich</Mitarbeiter>
</Kollegen>
<Ansprechpartner Ident="A_2">Ludwig Noresponsable</Ansprechpartner>
<Adresse>
<Strasse>An der Waterkant 15</Strasse>
<Ort>45555 Hamburg</Ort>
</Adresse>
<Kostenvoranschlag>30 000000</Kostenvoranschlag>
</Gruppe>
<Team>
<Name>Controlling</Name>
<Ansprechpartner>Werner Kostfix</Ansprechpartner>
<Telefon>030-4544332</Telefon>
</Team>
</Projekte>

Machen wir uns an einem einfachen Beispiel klar, wie die Dinge zusammenhängen. Unser erstes XSLT-Stylesheet sieht so aus:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- Durch die eingebauten Template Rules, werden alle Elemente gezeigt (Attribute nicht !), auch wenn keine Templates für das Element angegeben ist -->
<xsl:template match="/">
<!-- Der Punkt steht für den aktuellen Knoten -->
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>

Die XML-Datei speichern wir unter Unternehmensberatung in dem Ordner ab, wo auch die heruntergeladene Datei saxon.exe liegt. Das oben stehende XSLT-Stylesheet speichern wir in dem gleichen Ordner unter dem Namen test.xsl ab. Es kann im Einzelfalle Schwierigkeiten geben, Dateien mit der Endung .xml bzw. .xsl abzuspeichern. Windows kennt diese Endung nicht und fügt folglich ein .txt an, was wir im Moment nicht brauchen. Um das zu verhindern, setzt man den Namen in Anführungsstriche, man speichert also nicht Unternehmensberatung.xml ab sondern "Unternehmensberatung.xml" und nicht test.xsl sondern "test.xsl". Sind alle drei Dateien im gleichen Ordner, wechseln wir mit der Dos Box (Eingabeaufforderung) in diesen Ordner. Dies machen wir z.B. mit cd saxon wenn wir uns nach öffnen der Box in c:\ befinden. Wenn nicht gehen wir mit cd.. zuerst nach c:\ und geben dann cd saxon ein. Nehmen wir an, der Ordner, wo wir alle Dateien abgelegt haben, heisst saxon2. In diesem Fall wechseln wir in den Ordner saxon2 und geben danach saxon Unternehmensberatung.xml test.xsl ein, so dass wir folgendes Bild erhalten:

c:\saxon2>saxon Unternehmensberatung.xml test.xsl

Anschliessend drücken wir die return-Taste. Wir sehen, dass der komplette Inhalt, dass heisst der Text aller Knoten ausgedruckt wird, allerdings nicht die Attribute. Schauen wir uns das XSLT-Stylesheet im Detail an:

1) <?xml version="1.0" encoding="iso-8859-1"?>
2) <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
3) <!-- Durch die eingebauten Template Rules, werden alle Elemente gezeigt (Attribute nicht !),auch wenn keine Templates für das Element angegeben ist -->
4) <xsl:template match="/">
5) <xsl:value-of select="."/>
6) </xsl:template>
7) </xsl:stylesheet>

Aufbau eines XSLT-Stylesheet

Wie zu erkennen, muss ein XSLT-Stylesheet ebenfalls den Ansprüchen an ein wohlgeformtes XML-Dokument genügen. Jeder öffnende Tag muss also einen schliessenden Tag haben, bzw. wenn das nicht der Fall ist, muss er mit dem Slash ( / ) geschlossen werden.
1) allerdings gehört noch nicht zum eigentlichen Stylesheet und muss diesen Bedingungen nicht genügen. Hier wird angegeben, um welche Version es sich handelt, also um 1.0, wobei es im Moment nur diese gibt. Es folgt die Angabe des Zeichensatzes, wir wählen iso-8859-1, weil wir dann Umlaute, scharf s etc. verwendet können. In
2) geben wir mit xmlns:xsl="http://www.w3.org/1999/XSL/Transform" den Namespace an, dass heisst, dass alle Elemente, die zum Stylesheet gehören das Präfix xsl haben, wobei wir auch etwas anderes hätten wählen können. Entscheidend ist jetzt die Zeile
4). Mit der Funktion template match greifen wir einen Knoten, wobei innerhalb von template match festgelegt wird, was passieren soll, wenn dieser Knoten gefunden wird. In unserem Falle soll der Inhalt des Knotens angezeigt werden. Im Detail ist das verblüffend, weil wir ja den kompletten Inhalt des gesamten Dokumentes erhalten. Was passiert ist folgendes. Der Slash / besagt, dass an der Wurzel des Dokumentes gestartet werden soll, danach erfolgt keine weitere XPATH-Spezifikation, (für Details XPATH siehe Abfragen mit XPATH), das heisst, wir erhalten den Knoten Projekte, den Wurzelknoten des XML-Dokumentes und alle Kindknoten dieses Knotens werden angezeigt, bzw. deren Text.

Die Funktion template match

Was in einer template match Anweisung definiert wird, wird so oft ausgeführt, wie Knoten dieses Typs vorhanden sind.

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/Projekte/Gruppe">
Hallo
</xsl:template>
</xsl:stylesheet>

Wie oft druckt dieses Template hallo ? Zweimal, da es zwei Knoten dieses Typs gibt, also Knoten mit dem Namen Gruppe. Genau genommen erhalten wir aber dies:

C:\saxon2>saxon Unternehmensberatung.xml test.xsl
<?xml version="1.0" encoding="utf-8"?>
Hallo
Hallo

Controlling
Werner Kostfix
030-4544332
C:\saxon2>

Wir erhalten also auch noch alles unterhalb des Knotens Team. Wie das ? Die Lösung ist einfach. Ist für einen bestimmten Knoten kein Template definiert, so wird er nicht etwa, wie man vermuten würde, nicht angezeigt, sondern er wird angezeigt. Für den Knoten Team haben wir aber kein Template definiert, folglich wird es angezeigt. Wenn wir auf alle Knoten Mitarbeiter zugreifen wollen, also zum Beispiel für jeden Knoten einmal hallo sagen wollen, können wir das so machen:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:apply-templates select="/Projekte/Gruppe/Kollegen/Mitarbeiter"/>
</xsl:template>

<xsl:template match="Mitarbeiter">
Hallo
</xsl:template>
</xsl:stylesheet>

Wie oft werden wir jetzt Hallo erhalten ? Nun, sechmal, weil wir sechs Mitarbeiter haben. Die Syntax ist nun etwas komisch. Zuerst mal müssen wir uns klar machen, dass sowas nicht zum gewünschten Ziel führt:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/Projekte/Gruppe/Kollegen/Mitarbeiter">
Hallo
</xsl:template>
</xsl:stylesheet>

Auch hier erhalten wir zwar sechsmal hallo für die Mitarbeiter, aber zusätzlich noch alle anderen Knoten (Gruppenname, Ansprechpartner, Adresse, Budget etc.). Wer sich das genau anschauen will, kann es auch fest auf die Platte drucken. Um dies zu realisieren ist ein Parameter mehr nötig, nämlich die Datei, in die gedruckt werden soll. Das sieht dann so aus:

C:\saxon2>saxon Unternehmensberatung.xml test.xsl >banane.xml

Nachdem wir nun festgestellt haben, dass es so nicht geht, gehen wir das Stylesheet mit dem wir unser Ziel erreichen, nämlich für jedes Auftreten des Knotens Mitarbeiter hallo zu sagen nochmal durch.

1) <?xml version="1.0" encoding="iso-8859-1"?>
2) <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
3) <xsl:template match="/">
4) <xsl:apply-templates select="/Projekte/Gruppe/Kollegen/Mitarbeiter"/>
5) </xsl:template>
6) <xsl:template match="Mitarbeiter">
7) Hallo
8) </xsl:template>
9) </xsl:stylesheet>

Entscheidend sind die Zeilen 3) bis 4). Dadurch, dass wir ein Template für den Wurzelknoten bestimmen, ist garantiert, dass es keinen Knoten mehr gibt, für den kein Template vorliegt, dass also nichts erscheint, was nicht erscheinen soll. Innerhalb dieser Templatedefinition rufen wir mit apply-templates eine neues Template auf, nämlich das Template Mitarbeiter, dass dann wiederum Hallo sagt. Das ist etwas ungewöhnlich, wenn man in den Kategorien einer Programmiersprache denkt, weil es ja de facto eine Schleife ist. Das gleiche kann man auch mit einem for-each Konstrukt erreichen. Das sieht dann so aus:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="Projekte/Gruppe/Kollegen/Mitarbeiter">
Hallo
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Die Wirkung ist die gleiche, allerdings ist die Syntax leichter zu lesen (für jedes (for each) Element mit dem Namen Mitarbeiter mach das und das..), weil es sich um eine "normale" foreach Schleife handelt. Die Anweisung apply-templates ist aber flexibler, insbesondere dann, wenn die Abfragen komplexer werden. Nehmen wir an, wir wollen zuerst die Mitarbeiter einer Gruppe sehen und direkt anschliessend den dazugehörigen Ansprechpartner. Dies ist so nicht zu realisieren:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:apply-templates select="/Projekte/Gruppe/Kollegen/Mitarbeiter"/>
<xsl:apply-templates select="/Projekte/Gruppe/Ansprechpartner"/>
</xsl:template>

<xsl:template match="Mitarbeiter">
Mitarbeiter: <xsl:value-of select="."/>
</xsl:template>

<xsl:template match="Ansprechpartner">
Ansprechpartner: <xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>

Das führt nicht zum Ziel. Zuerst erhalten wir alle Mitarbeiter und anschliessend alle Ansprechpartner. Wir wollen aber die ersten drei Mitarbeiter, dann den dazugehörigen Ansprechpartner, dann wieder drei Mitarbeiter und dann wieder den dazugehörigen Ansprechpartner. Was wir erhalten ist das:

C:\saxon2>saxon Unternehmensberatung.xml test.xsl
<?xml version="1.0" encoding="utf-8"?>
Mitarbeiter: Werner Lepinski
Mitarbeiter: Erika Saufwech
Mitarbeiter: Hans Geldfliech
Mitarbeiter: Werner Nordflut
Mitarbeiter: Marina Meimportauncarajo
Mitarbeiter: Peter Wessnich
Ansprechpartner: Otto Moltoimportante
Ansprechpartner: Ludwig Noresponsable
C:\saxon2>

Und das wollen wir nicht. Um zu erreichen was wir wollen, brauchen wir dieses Stylesheet:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:apply-templates select="/Projekte/Gruppe"/>
</xsl:template>

<xsl:template match="Gruppe">
<xsl:apply-templates select="Kollegen/Mitarbeiter"/>
<xsl:apply-templates select="Ansprechpartner"/>
</xsl:template>

<xsl:template match="Mitarbeiter">
Mitarbeiter: <xsl:value-of select="."/>
</xsl:template>

<xsl:template match="Ansprechpartner">
Ansprechpartner: <xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>

Das Programm macht dann was wir uns vorstellen. Das Resultat sieht so aus:

<?xml version="1.0" encoding="utf-8"?>
Mitarbeiter: Werner Lepinski
Mitarbeiter: Erika Saufwech
Mitarbeiter: Hans Geldfliech
Ansprechpartner: Otto Moltoimportante
Mitarbeiter: Werner Nordflut
Mitarbeiter: Marina Meimportauncarajo
Mitarbeiter: Peter Wessnich
Ansprechpartner: Ludwig Noresponsable
C:\saxon2>

Und das ist das, was wir wollen. Alternativ hätte wir es auch so machen können:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:apply-templates select="/Projekte/Gruppe"/>
</xsl:template>

<xsl:template match="Gruppe">
<xsl:for-each select="Kollegen/Mitarbeiter">
Mitarbeiter: <xsl:value-of select="."/>
</xsl:for-each>
Ansprechpartner: <xsl:value-of select="Ansprechpartner"/>
</xsl:template>
</xsl:stylesheet>

Die Logik dahinter ist einfach. Wir haben zwei Knoten Gruppe und diese zwei Knoten rufen wir auf. Für jeden Knoten Gruppe rufen wir dann die Mitarbeiter und die Ansprechpartner auf.

Zugriff auf einen bestimmten Knoten aus einer Gruppe gleichnamiger Knoten

Wenn wir nur die zweite Gruppe erfassen wollen, also nur die Mitarbeiter und den Ansprechpartner der zweiten Gruppe, dann sieht das so aus:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:apply-templates select="/Projekte/Gruppe[2]"/>
</xsl:template>

<xsl:template match="Gruppe">
<xsl:for-each select="Kollegen/Mitarbeiter">
Mitarbeiter: <xsl:value-of select="."/>
</xsl:for-each>
Ansprechpartner: <xsl:value-of select="Ansprechpartner"/>
</xsl:template>
</xsl:stylesheet>

Entscheidend ist hierbei die XPATH-Definition /Projekte/Gruppe[2] mit der wir sofort auf den zweiten Knoten zugreifen.

Transformation in ein HTML-Dokument

Bis jetzt haben wir noch nicht viel transformiert, wir haben uns lediglich damit beschäftigt, Zugriff auf die einzelnen Knoten zu erhalten, was allerdings die conditio sine qua non jeder Transformation ist. Wollen wir alle Mitarbeiter jeder Gruppe rausfischen und dann dazu noch den Ansprechpartner und das alles als HTML-Seite dann können wir das so machen:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html><head><title>Alles HTML</title></head><body>
<xsl:apply-templates select="/Projekte/Gruppe"/>
</body></html>
</xsl:template>

<xsl:template match="Gruppe">
<table>
<xsl:for-each select="Kollegen/Mitarbeiter">
<tr><td bgcolor="yellow">Mitarbeiter: <xsl:value-of select="."/></td></tr>
</xsl:for-each>
<tr><td bgcolor="orange">Ansprechpartner: <xsl:value-of select="Ansprechpartner"/></td></tr>
</table>
</xsl:template>
</xsl:stylesheet>

Wir können dieses XSLT-Stylesheet dann auslösen. Am besten wir drucken es in eine HTML-Seite, damit wir es uns anschliessend gleich mit dem Browser betrachten können.

C:\saxon2>saxon Unternehmensberatung.xml test.xsl >test.html

Wir erhalten als Ergebnis:

Um das zu verstehen, muss man wissen, welcher Knoten wie oft aufgerufen wird. Der Knoten / also der Wurzelknoten, wird nur ein einziges Mal aufgerufen. Folglich müssen hier die Wurzelknoten des HTML-Dokumentes untergebracht werden. Jede Gruppe ist ein eigener table, folglich müssen die table-tags in das aufgerufene Template. Und die Zeilendefinitionen an die Stelle, wo die Mitarbeiter aufgerufen werden.

Das Ergebnis der Transformation, den Ergebnisbaum, direkt im Browser zeigen

Man kann sich das auch direkt im Browser anschauen, allerdings braucht man dann einen XSLT-Parser, der clientseitig arbeitet. Microsoft stellt einen solchen zur Verfügung, er heisst MSXML und kann hier downgeloadet werden. Damit kann man dann XML-Dateien via XSL transformieren und direkt im Browser anzeigen. Allerdings ist der Ansatz reichlich sinnlos, weil z.B. Netscape-Browser das nicht unterstützen. Will man den Ergebnisbaum, also die transformierte XML-Datei direkt im Browser zeigen, ist es günstiger man generiert sie auf dem Server und schickt sie dann an den Client. Wie das geht, siehe Auslesen eines XML Dokumentes mit XSLT unter Verwendung von Sablotron und PHP und Auslesen eines XML-Dokumentes mit XSLT unter Verwendung von Perl XSLT. Der Vollständigkeit halber zeigen wir den Ansatz. Eigentlich muss hierfür lediglich MSXML geladen sein und die XML-Datei modifiziert werden.

<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet href="test.xsl" type="text/xsl"?>
<Projekte>
<Gruppe>
<Gruppenname stand="abgeschifft">Berliner Verwaltungsreform</Gruppenname>
<Kollegen>
<Mitarbeiter Firma="Preis Wasserhaus">Werner Lepinski</Mitarbeiter>
<Mitarbeiter>Erika Saufwech</Mitarbeiter>
<Mitarbeiter>Hans Geldfliech</Mitarbeiter>
</Kollegen>
<Ansprechpartner Telefon="030-435555" Ident="A_1">Otto Moltoimportante</Ansprechpartner>
<Adresse>
<Strasse Gegend="teures Pflaster">Kurfürstendamm 5</Strasse>
<Ort>13453 Berlin</Ort>
</Adresse>
<Budget>40 000000</Budget>
<Kommentar>Alles wird gut</Kommentar>
</Gruppe>
<Gruppe>
<Gruppenname>Hamburger Verwaltungschaos </Gruppenname>
<Kollegen>
<Mitarbeiter Firma="Arthur der Kleine">Werner Nordflut</Mitarbeiter>
<Mitarbeiter>Marina Meimportauncarajo</Mitarbeiter>
<Mitarbeiter>Peter Wessnich</Mitarbeiter>
</Kollegen>
<Ansprechpartner Ident="A_2">Ludwig Noresponsable</Ansprechpartner>
<Adresse>
<Strasse>An der Waterkant 15</Strasse>
<Ort>45555 Hamburg</Ort>
</Adresse>
<Kostenvoranschlag>30 000000</Kostenvoranschlag>
</Gruppe>
<Team>
<Name>Controlling</Name>
<Ansprechpartner>Werner Kostfix</Ansprechpartner>
<Telefon>030-4544332</Telefon>
</Team>
</Projekte>

Wie deutlich zu erkennen, wurde lediglich eine Zeile (die zweite) eingefügt. Man kann das jetzt so abspeichern und im Browser aufrufen.

Ermitteln des Wertes eines Attributes

Attribute sind in XPATH keine normalen Knoten. Will man sie abrufen bedarf es einer speziellen Syntax. Wenn wir alle Firmen rausfischen wollen, die ein Attribut von Mitarbeiter sind, dann können wir das so machen:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:apply-templates select="/Projekte/Gruppe/Kollegen/Mitarbeiter"/>
</xsl:template>

<xsl:template match="Mitarbeiter">
Hallo <xsl:value-of select="@Firma"/>
</xsl:template>
</xsl:stylesheet>

Was wir erhalten ist sowas

C:\saxon2>saxon Unternehmensberatung.xml test.xsl
<?xml version="1.0" encoding="utf-8"?>
Hallo Preis Wasserhaus
Hallo
Hallo
Hallo Arthur der Kleine
Hallo
Hallo
C:\saxon2>

Das ist fast was wir wollen, aber nicht ganz. Das wir für Mitarbeiter ein Template definiert haben, wird dieses so oft aufgeführt, wie Mitarbeiter vorhanden sind. Also sechs mal. Nur zwei davon haben aber tatsächlich ein Attribut, die anderen laufen im Leerlauf. Das Hallo kann man natürlich wegmachen, aber sauber ist es nicht. Wir wollen nur die Attribute sehen. Korrekt ist also so etwas:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="/Projekte/Gruppe/Kollegen/Mitarbeiter[@Firma]">
Hallo <xsl:value-of select="@Firma"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Wir erhalten dann was wir uns wünschen.

C:\saxon2>saxon Unternehmensberatung.xml test.xsl
<?xml version="1.0" encoding="utf-8"?>
Hallo Preis Wasserhaus
Hallo Arthur der Kleine
C:\saxon2>

Mehrere Attribute eines Knotens anzeigen lassen

Die Probleme können komplexer sein, der Phantasie sind keine Grenzen gesetzt. Man kann den Namen eines Mitarbeiters z.B. nur sehen wollen, wenn er zur Firma XY gehört, man kann alle Attribute sehen wollen, man kann sich für die Summe von Attributen interessieren usw.usw. Um dies zu zeigen, modifizieren wir unser Beispiel. Für eine detaillierte Darstellung siehe Abfragen mit XPATH.

<?xml version="1.0" encoding="ISO-8859-1"?>
<Projekte>
<Gruppe>
<Gruppenname stand="abgeschifft">Berliner Verwaltungsreform</Gruppenname>
<Kollegen>
<Mitarbeiter Firma="Preis Wasserhaus" Summe="90000">Werner Lepinski</Mitarbeiter>
<Mitarbeiter Firma="Schitag Ernst und Jung" status="ausgeliehen" Summe="20000">Erika Saufwech</Mitarbeiter>
<Mitarbeiter Summe="27000">Hans Geldfliech</Mitarbeiter>
</Kollegen>
<Ansprechpartner Telefon="030-435555" Ident="A_1">Otto Moltoimportante</Ansprechpartner>
<Adresse>
<Strasse Gegend="teures Pflaster">Kurfürstendamm 5</Strasse>
<Ort>13453 Berlin</Ort>
</Adresse>
<Budget>40 000000</Budget>
<Kommentar>Alles wird gut</Kommentar>
</Gruppe>
<Gruppe>
<Gruppenname>Hamburger Verwaltungschaos </Gruppenname>
<Kollegen>
<Mitarbeiter Firma="Arthur der Kleine" Summe="30000">Werner Nordflut</Mitarbeiter>
<Mitarbeiter Firma="Wertarbeit" status="ausgeliehen" Summe="40000">Marina Meimportauncarajo</Mitarbeiter>
<Mitarbeiter Firma="Preis Wasserhaus" Summe="70000" status="ausgeliehen">Peter Wessnich</Mitarbeiter>
</Kollegen>
<Ansprechpartner Ident="A_2">Ludwig Noresponsable</Ansprechpartner>
<Adresse>
<Strasse>An der Waterkant 15</Strasse>
<Ort>45555 Hamburg</Ort>
</Adresse>
<Kostenvoranschlag>30 000000</Kostenvoranschlag>
</Gruppe>
<Team>
<Name>Controlling</Name>
<Ansprechpartner>Werner Kostfix</Ansprechpartner>
<Telefon>030-4544332</Telefon>
</Team>
</Projekte>

Alle Mitarbeiter und alle dazugehörigen Attribute ermitteln.

Will man sich alle Mitarbeiter zeigen lassen nebst alle Attributen, dann kann man sowas machen.


<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="/Projekte/Gruppe/Kollegen/Mitarbeiter">
Mitarbeiter <xsl:value-of select="."/>
<xsl:apply-templates select="./attribute::*"/>
</xsl:for-each>
</xsl:template>
<xsl:template match="attribute::*">
Attribut <xsl:value-of select="name()"/> Wert <xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>

Das Ergebnis sieht dann so aus:

C:\saxon2>saxon Unternehmensberatung.xml test.xsl
<?xml version="1.0" encoding="utf-8"?>
Mitarbeiter Werner Lepinski
Attribut Firma Wert Preis Wasserhaus
Attribut Summe Wert 90000
Mitarbeiter Erika Saufwech
Attribut Firma Wert Schitag Ernst und Jung
Attribut status Wert ausgeliehen
Attribut Summe Wert 20000
Mitarbeiter Hans Geldfliech
Attribut Summe Wert 27000
Mitarbeiter Werner Nordflut
Attribut Firma Wert Arthur der Kleine
Attribut Summe Wert 30000
Mitarbeiter Marina Meimportauncarajo
Attribut Firma Wert Wertarbeit
Attribut status Wert ausgeliehen
Attribut Summe Wert 40000
Mitarbeiter Peter Wessnich
Attribut Firma Wert Preis Wasserhaus
Attribut Summe Wert 70000
Attribut status Wert ausgeliehen
C:\saxon2>

Aufsummieren der Werte eines Attributes

Will man die Summen des Attributs Summe der Mitarbeiter erhalten (90000 + 20000+270000+300000+400000+700000=277000) so kann man das mit diesem Stylesheet erreichen.

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:value-of select="sum(/Projekte/Gruppe/Kollegen/Mitarbeiter/attribute::Summe)"/>
</xsl:template>
</xsl:stylesheet>

Auslesen aller gleichnamigen Knoten in unterschiedlichen Gruppen

Will man alle Ansprechpartner rausfischen, dann ist das im obigen Beispiel nicht so einfach, da sich einer davon ja auch in Team befindet. Eine XPATH-Abfrage nach dem Schema /Projeke/Gruppe/Ansprechpartner funktionniert also nicht. Es gibt aber eine einfache Möglichkeit, dies zu lösen.

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="/Projekte/child::*/Ansprechpartner">
hallo <xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Man erhält dann alle Ansprechpartner. Entscheidend ist hierbei die XPATH-Abfrage child::*. child steht für die Kindknoten und mit dem * geben wir kund, dass wir alle Kindknoten haben wollen, in unserem Falle also Gruppe und Team. Alternativ hätte man auch mit oder (das Zeichen für oder ist die Pipe |) arbeiten können.

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="/Projekte/Gruppe/Ansprechpartner | /Projekte/Team/Ansprechpartner ">
hallo <xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Wir suchen jetzt entweder /Projekte/Gruppe/Ansprechpartner oder /Projekte/Team/Ansprechpartner. Eine dritte Möglichkeit wäre gewesen, mit einer Achse zu arbeiten, in diesem Falle mit descendant. Diese Achse erfasst alle Knoten unterhalb des Referenzknotens. Sie erfasst also auch die Enkelknoten des Referenzknotens. Da sowohl die Kindknoten als auch die Referenzknoten erfasst werden, erhalten wir sowohl so

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="/Projekte/descendant::*/Ansprechpartner">
hallo <xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

wie auch so

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="/descendant::*/Ansprechpartner">
hallo <xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

das richtige Ergebnis.

Navigieren mit Hilfe von Achsen

XPATH kennt sogenannte Achsen, die man nutzen kann, um innerhalb eines Dokumentes zu navigieren. Betrachten wir das genauer.
Die Achse parent
Parent ermittelt den Elternknoten eines Knotens. Wenn wir uns zum Beispiel dafür interessieren, ob der Ansprechpartner innerhalb von Team oder Gruppe ist, dann können wir so etwas tun.


<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="/Projekte/child::*/Ansprechpartner">
Wo: <xsl:value-of select="name(parent::node())"/>
hallo <xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Die Achse following
Die Achse following erfasst die Knoten rechts vom aktuellen Knoten. Würde man sich, aus bislang unbekannten Gründen, dafür interessieren, wie der Schwesternknoten des Ansprechpartners heisst, also Adresse, dann kann man sowas machen:


<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="/Projekte/child::*/Ansprechpartner">
Wo: <xsl:value-of select="name(following::*[position()=1])"/>
hallo <xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>


Zu berücksichtigen ist, dass following nicht nur den Schwesternknoten schnappt, sondern auch alle Knoten unter den Schwesternknoten, wenn der Schwesternknoten
also Adresse ist, dann wird die Strasse und der Ort mitgeschnappt. Wir wollen aber nur den Namen von dem Schwesternknoten wissen, aus wie gesagt unbekannten Gründen,
und fischen uns deshalb von allen Knoten (*) den raus, der an erster Position steht. Auf diese Weise erhalten wir dann sowas.


C:\saxon2>saxon Unternehmensberatung.xml test.xsl
<?xml version="1.0" encoding="utf-8"?>
Wo: Adresse
hallo Otto Moltoimportante
Wo: Adresse
hallo Ludwig Noresponsable
Wo: Telefon
hallo Werner Kostfix
C:\saxon2>

Um noch mal zu verdeutlichen, dass die Achse following den Schwesternknoten plus die Kindknoten des Schwesternknoten rausfischt, lassen wir uns einen Kindknoten des Schwesternknoten ausdrucken.

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="/Projekte/child::*/Ansprechpartner">
Wo: <xsl:value-of select="name(following::*[position()=2])"/>
hallo <xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Wir greifen jetzt auf den zweiten Knoten von following zu, dies ist ein Kindknoten von Adresse, genau genommen Strasse. Bei Telefon, die Schwester von Hans Kostfix, klappt das nicht, weil Telefon gar keinen Kindknoten hat. Das Ergebnis sieht so aus:

C:\saxon2>saxon Unternehmensberatung.xml test.xsl
<?xml version="1.0" encoding="utf-8"?>
Wo: Strasse
hallo Otto Moltoimportante
Wo: Strasse
hallo Ludwig Noresponsable
Wo:
hallo Werner Kostfix

Die Achse following-sibling

following-sibling erfasst alle Schwesternknoten, allerdings ohne die Kindknoten dieser Schwestern.

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="/Projekte/child::*/Ansprechpartner">
Wo: <xsl:value-of select="name(following-sibling::*[position()=2])"/>
hallo <xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Das führt zum gleichen Ergebnis wie oben.

C:\saxon2>C:\saxon2>saxon Unternehmensberatung.xml test.xsl
<?xml version="1.0" encoding="utf-8"?>
Wo: Budget
hallo Otto Moltoimportante
Wo: Kostenvoranschlag
hallo Ludwig Noresponsable
Wo:
hallo Werner Kostfix
C:\saxon2>

Unterschied zwischen der Achse following und following-sibling
Der Unterschied zwischen following und following-sibling ist nicht ohne weiteres einzusehen. following hat alle Schwesternknoten rechts vom Startknoten und die Kindsknoten dieser Schwestern. In unserem Falle ist der Starknoten Ansprechpartner. following-sibling hat alle nur die Schwesternknoten, ohne die dazugehörigen Kindsknoten. Machen wir uns die Unterschiede an einem Beispiel klar.


<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="/Projekte/child::*/Ansprechpartner">
Wo: <xsl:value-of select="name(following::*[position()=2])"/>
hallo <xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Hier werden die Kindsknoten miterfasst, folglich ist der zweite Knoten ein Kind von Adresse, genaugenommen Strasse. Wir erhalten das.

C:\saxon2>saxon Unternehmensberatung.xml test.xsl
<?xml version="1.0" encoding="utf-8"?>
Wo: Strasse
hallo Otto Moltoimportante
Wo: Strasse
hallo Ludwig Noresponsable
Wo:
hallo Werner Kostfix
C:\saxon2>

Mit following-sibling steht an zweiter Position aber nicht ein Kind des Schwesternknoten sondern der nächste Schwesternknoten, also Budget in der ersten Gruppe und Kostenvoranschlag in der zweiten Gruppe und nichts in der dritten.

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="/Projekte/child::*/Ansprechpartner">
Wo: <xsl:value-of select="name(following-sibling::*[position()=2])"/>
hallo <xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Lösen wir das Stylesheet aus, erhalten wir das.

C:\saxon2>saxon Unternehmensberatung.xml test.xsl
<?xml version="1.0" encoding="utf-8"?>
Wo: Budget
hallo Otto Moltoimportante
Wo: Kostenvoranschlag
hallo Ludwig Noresponsable
Wo:
hallo Werner Kostfix
C:\saxon2>

Um mit following bis zur Position Budget und Kostenvoranschlag vorzurücken müsste als Position 4 angegeben werden.

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="/Projekte/child::*/Ansprechpartner">
Wo: <xsl:value-of select="name(following::*[position()=4])"/>
hallo <xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Das führt dann zum gleichen Ergebnis wie oben.

C:\saxon2>saxon Unternehmensberatung.xml test.xsl
<?xml version="1.0" encoding="utf-8"?>
Wo: Budget
hallo Otto Moltoimportante
Wo: Kostenvoranschlag
hallo Ludwig Noresponsable
Wo:
hallo Werner Kostfix
C:\saxon2>

Die Achse preceding

preceding bzw. preceding-sibling ist das Gegenstück following bzw. following-sibling . preceding erfasst alle Schwesternknoten die links vom Ausgangsknoten stehen, sowie alle Kindknoten dieser Schwesternknoten. preceding-sibling erfasst alle Schwesternknoten links vom Ausgangsknoten ohne die Kindknoten dieser Schwesterknoten.

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="/Projekte/child::*/Ansprechpartner">
Wo: <xsl:value-of select="name(preceding::*[position()=1])"/>
hallo <xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Wir erhalten

C:\saxon2>saxon Unternehmensberatung.xml test.xsl
<?xml version="1.0" encoding="utf-8"?>
Wo: Mitarbeiter
hallo Otto Moltoimportante
Wo: Mitarbeiter
hallo Ludwig Noresponsable
Wo: Name
hallo Werner Kostfix
C:\saxon2>

Das verblüfft uns erstmal. Der unmittelbar links von Ansprechpartner liegende Schwesternknoten ist Kollege. Mitarbeiter ist eine Hierarchistufe weiter unten und kein Schwesternknoten. preceding zeigt die Knoten aber in umgekehrter Dokumenten-Reihenfolge. Wenn also der Knoten Kollegen selber wieder drei Knoten hat, dann ist er selber der vierte. Da erwartete Ergebnis erhalten wir also so:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="/Projekte/child::*/Ansprechpartner">
Wo: <xsl:value-of select="name(preceding::*[position()=4])"/>
hallo <xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Ein XML-Dokument mit XSLT modifizieren

Im Prinzip, wenn das auch in der Literatur weit seltener beschrieben wird, ist es genauso spannend ein XML-Dokument zu verändern wie auszulesen.

Ein Element hinzufügen

Will man einem XML-Dokument ein Element hinzufügen, so kann man das so machen:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/Projekte/Gruppe[2]/Kollegen">
<xsl:copy>
<xsl:element name="Mitarbeiter">
<xsl:attribute name="Firma">Treue Arbeit GmbH</xsl:attribute>
Franz Pingelkniek
</xsl:element>
<xsl:apply-templates select="/Projekte/Gruppe[2]/Kollegen/Mitarbeiter" />
</xsl:copy>

</xsl:template>

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

</xsl:stylesheet>

Diese Variante funktioniert sowohl mit dem saxon-Prozessor als auch mit sablotron, Informationen zu sablotron siehe PHP-Handbuch.
Das Hinzufügen eines Elementes zerfällt in zwei Prozesse.

1. Hinzufügen des Elementes an der richtigen Stelle
2. das ganze Dokument neu drucken.

Mit /Projekte/Gruppe[2]/Kollegen/Mitarbeiter wählen wir die Stelle aus, wo wir unser neues Element einfügen wollen. Hierbei ist zu berücksichtigen, dass der Befehl xsl:copy an dieser Stelle die bisherigen Inhalte durch neue Inhalte ersetzt. Das heisst, die neuen Inhalte müssen reingeschrieben werden und die alten wieder zurückkopiert werden. Mit xsl:element fügen wird den neuen Inhalt ein und setzen bei der Gelegenheit mit xsl:attribute auch ein Attribut. Würden wir jetzt die alten Inhalte nicht zurückschreiben, hätten wir nur das neue Element drin und die alten nicht mehr. Deshalb kopieren wir mit /Projekte/Gruppe[2]/Kollegen/Mitarbeiter die alten Inhalte zurück. Das heisst, der Kindknoten von Mitarbeiter wurde komplett ausgetauscht. Anschliessend wird im zweiten Teil das komplette, modifizierte, Dokument neu geschrieben. Hierbei ist zu beachten, dass xsl:copy keine Kindknoten mitkopiert. Wir müssen also jeden Knoten einzeln erfassen und kopieren. Daher die Syntax @* und node(). Wir können das mit dem gewohnten Schema auslösen

c:\saxon2\saxon Unternehmensberatung.xml text.xsl >Unternehmensberatung2.xml

Unternehmensberatung2.xml ist dann das modifiezierte Dokument. Es hat folgendes Aussehen.

<?xml version="1.0" encoding="utf-8"?><Projekte>
<Gruppe>
<Gruppenname stand="abgeschifft">Berliner Verwaltungsreform</Gruppenname>
<Kollegen>
<Mitarbeiter Firma="Preis Wasserhaus" Summe="90000">Werner Lepinski</Mitarbeiter>
<Mitarbeiter Firma="Schitag Ernst und Jung" status="ausgeliehen" Summe="20000">Erika Saufwech</Mitarbeiter>
<Mitarbeiter Summe="27000">Hans Geldfliech</Mitarbeiter>
</Kollegen>
<Ansprechpartner Telefon="030-435555" Ident="A_1">Otto Moltoimportante</Ansprechpartner>
<Adresse>
<Strasse Gegend="teures Pflaster">Kurfürstendamm 5</Strasse>
<Ort>13453 Berlin</Ort>
</Adresse>
<Budget>40 000000</Budget>
<Kommentar>Alles wird gut</Kommentar>
</Gruppe>
<Gruppe>
<Gruppenname>Hamburger Verwaltungschaos </Gruppenname>
<Kollegen>
<Mitarbeiter Firma="Treue Arbeit GmbH">Franz Pingelkniek</Mitarbeiter>
<Mitarbeiter Firma="Arthur der Kleine" Summe="30000">Werner Nordflut</Mitarbeiter>
<Mitarbeiter Firma="Wertarbeit" status="ausgeliehen" Summe="40000">Marina Meimportauncarajo</Mitarbeiter>
<Mitarbeiter Firma="Preis Wasserhaus" Summe="70000" status="ausgeliehen">Peter Wessnich</Mitarbeiter>
</Kollegen>
<Ansprechpartner Ident="A_2">Ludwig Noresponsable</Ansprechpartner>
<Adresse>
<Strasse>An der Waterkant 15</Strasse>
<Ort>45555 Hamburg</Ort>
</Adresse>
<Kostenvoranschlag>30 000000</Kostenvoranschlag>
</Gruppe>
<Team>
<Name>Controlling</Name>
<Ansprechpartner>Werner Kostfix</Ansprechpartner>
<Telefon>030-4544332</Telefon>
</Team>

Wie deutlich zu erkennen, wurde in der zweiten Gruppe der Franz Pingelkniek eingefügt.

Ändern eines Elementes

Um ein Element zu ändern brauchen wir im ersten Teil kein xsl:copy. xsl:element überschreibt das angesteuerte Element. Um ein Element zu ändern,
z.B. den Peter Wessnich zu ersetzen durch den Franz Pingelkniek, brauchen wir etwas in der Art:


<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/Projekte/Gruppe[2]/Kollegen/Mitarbeiter[3]">
<xsl:element name="Mitarbeiter">
<xsl:attribute name="Firma">Treue Arbeit GmbH</xsl:attribute>
Franz Pingelkniek
</xsl:element>
</xsl:template>

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

Bei dieser Variante wird einfach der dritte Mitarbeiter durch ein neues Element ersetzt.

Löschen eines Elementes

Dies ist der denkbar einfachste Fall. Wir schreiben ein Template für das zu löschende Element, aber innerhalb dieses Templates machen wir nix, dann ist es eben weg.
Mit dem Skript unten zum Beispiel wird der Mitarbeiter Marina Meimportauncarajo gelöscht.

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/Projekte/Gruppe[2]/Kollegen/Mitarbeiter[2]">
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

Ein Element innerhalb des Dokumentes umpflanzen

Man muss sich im Klaren sein, dass die einfache Lösung, die einem sofort einfällt, nicht funktioniert. Wir wollen den zweiten Mitarbeiter in der ersten Gruppe, die Erika Saufwech, aus der ersten Gruppe ausschneiden und sie in die zweite Gruppe setzten.

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/Projekte/Gruppe[2]/Kollegen">
<xsl:copy>
<xsl:apply-templates select="/Projekte/Gruppe[1]/Kollegen/Mitarbeiter[2]"/>
<xsl:apply-templates select="/Projekte/Gruppe[2]/Kollegen/Mitarbeiter"/>
</xsl:copy>
</xsl:template>

<xsl:template match="/Projekte/Gruppe[1]/Kollegen/Mitarbeiter[2]">
</xsl:template>

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

</xsl:stylesheet>

Zwar wird das zweite Element, die Erika Saufwech gelöscht und die Elemente von der Gruppe zwei werden auch zurückkopiert, aber die Erika Saufwech wird nicht reinkopiert. Warum ist irgendwie unklar. Problemlos läßt sich der dritte und der erste Mitarbeiter in die zweite Gruppe einbauen, aber das ist leider nicht das was wir wollen, wir wollen ja den Mitarbeiter, den wir oben gelöscht haben unten einbauen. Da diese einfache Lösung nicht funktioniert, brauchen wir so was in der Art:

<xsl:template match="/Projekte/Gruppe[2]/Kollegen">
<xsl:copy>
<xsl:apply-templates select="/Projekte/Gruppe[2]/Kollegen/Mitarbeiter"/>
<xsl:apply-templates select="/Projekte/Gruppe[1]/Kollegen/Mitarbeiter[2]"/>
</xsl:copy>
</xsl:template>

<xsl:template match="/Projekte/Gruppe[1]/Kollegen">
<xsl:copy>
<xsl:for-each select="Mitarbeiter">
<xsl:if test="position()!=2">
<xsl:apply-templates select="."/>
</xsl:if>
</xsl:for-each>
</xsl:copy>
</xsl:template>

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

</xsl:stylesheet>

Bei dieser Lösung werden die Mitarbeiter beider Gruppen komplett neu geschrieben. Wir kopieren also erstmal die Erika Saufwech plus die originären Mitarbeiter in den Knoten Mitarbeiter der ersten Gruppe. Anschliessend beschreiben wir den Knoten Mitarbeiter der ersten Gruppe, dass heisst wir kopieren in diesen Knoten alle Knoten ausser dem Knoten 2, der ja die Erika Saufwech ist, die wir in der ersten Gruppe nicht mehr haben wollen.

Elemente sortieren mit XSLT

Elemente sortieren ist relativ unproblematisch, zu mindestens in einfachen Fällen, und geht so:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="/Projekte/Gruppe/Kollegen/Mitarbeiter">
<xsl:sort select="."/>
Hallo <xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

xsl:sort kann Attribute haben, nämlich ascending, was der default-Wert ist, oder
descending, absteigend, was bedeutet, dass die Reichenfolge ZYXWVU ist.

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="/Projekte/Gruppe/Kollegen/Mitarbeiter">
<xsl:sort select="." order="descending"/>
Hallo <xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Datensätze nummerieren

Es kann interessant sein, die Datensätze bei der Ausgabe zu nummerieren. Das kann man dann so machen.

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="/Projekte/Gruppe/Kollegen/Mitarbeiter">
<xsl:sort select="." order="descending"/>
Hallo <xsl:value-of select="."/>(<xsl:value-of select="position()"/>)
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Bei Verwendung von number, kann man die Nummerierung feiner steuern, also z.B. mit römischen Ziffern, Buchstaben etc. Das sieht dann so aus:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="/Projekte/Gruppe/Kollegen/Mitarbeiter">
Hallo <xsl:value-of select="."/>(<xsl:number format="I" />)
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Leider entspricht das Ergebnis nicht unseren Erwartungen. Wir erhalten so was:

C:\saxon2>saxon Unternehmensberatung.xml test.xsl
<?xml version="1.0" encoding="utf-8"?>
Hallo Werner Lepinski(I)
Hallo Erika Saufwech(II)
Hallo Hans Geldfliech(III)
Hallo Werner Nordflut(I)
Hallo Marina Meimportauncarajo(II)
Hallo Peter Wessnich(III)
C:\saxon2>

Das heisst jede Gruppe wird für sich nummeriert. Will man tatsächlich alle durchnummerieren, kann man sowas machen:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="/Projekte/Gruppe/Kollegen/Mitarbeiter">
Hallo <xsl:value-of select="."/>(<xsl:number format="I" level="any" />)
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Will man nun so etwas machen, wie in Büchern üblich , also Kapitel und dann Unterkapitel, läßt sich auch das mit number realisieren.

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
<xsl:apply-templates select="/Projekte/Gruppe"/>
</xsl:template>

<xsl:template match="Gruppe">
Gruppe: <xsl:number format="1"/> <xsl:value-of select="node()"/>
<xsl:apply-templates select="Kollegen/Mitarbeiter"/>
</xsl:template>

<xsl:template match="Kollegen/Mitarbeiter">
<xsl:for-each select=".">
Hallo <xsl:value-of select="."/>(<xsl:number format="I" />)
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Man erhält dann, wenn das Beispiel von oben zugrunde liegt, das:

C:\saxon2>saxon Unternehmensberatung.xml test.xsl
<?xml version="1.0" encoding="utf-8"?>
Gruppe: 1
Hallo Werner Lepinski(I)
Hallo Erika Saufwech(II)
Hallo Hans Geldfliech(III)

Gruppe: 2
Hallo Werner Nordflut(I)
Hallo Marina Meimportauncarajo(II)
Hallo Peter Wessnich(III)

C:\saxon2>

Bedingte Anweisungen xsl:if und xsl:choose

Wir haben oben, bei der Erklärung von xsl:copy die if Bedingung schon verwendet, ohne sie genauer zu erklären. Im Grunde gibt es auch nicht viel zu erklären, sie entspricht weitgehend der if Bedingung, wie man sie aus allen Programmiersprachen kennt. Weitgehend identisch sind auch die Operatoren. Will man z.B. alle Mitarbeiter, also auch die Anprechpartner, sehen, die das Attribut Firma besitzen, kann man so was in der Art machen:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
<xsl:apply-templates select="/Projekte/Gruppe/Kollegen/Mitarbeiter | /Projekte/Gruppe/Ansprechpartner"/>
</xsl:template>
<xsl:template match="Mitarbeiter | Ansprechpartner">
<xsl:if test="name(./@*)='Firma'">
Hallo <xsl:value-of select="."/> (<xsl:value-of select="name(./@*)"/> ist <xsl:value-of select="./@Firma"/>)
</xsl:if>
</xsl:template>
</xsl:stylesheet>

Die Attribute sind Kindknoten des aktuellen Knotens, folglich kann man mit ./@* alle Attribute abgreifen. Mit name(./@*) hat man dann den Namen dieses Knotens. Das ist soweit ganz nett und funktioniert in diesem Beispiel auch, wir erhalten etwas, was richtig aussieht:

C:\saxon2>saxon Unternehmensberatung.xml test.xsl
<?xml version="1.0" encoding="utf-8"?>
Hallo Werner Lepinski (Firma ist Preis Wasserhaus)

Hallo Erika Saufwech (Firma ist Schitag Ernst und Jung)

Hallo Werner Nordflut (Firma ist Arthur der Kleine)

Hallo Marina Meimportauncarajo (Firma ist Wertarbeit)

Hallo Peter Wessnich (Firma ist Preis Wasserhaus)

C:\saxon2>saxon Unternehmensberatung.xml test.xsl

Leider ist es falsch. Es funktionniert nur, weil in diesem Beispiel Firma immer das erste Attribut ist, wir hätten im übrigen auch @Firma schreiben können. Es wird nur das erste Attribut aufgerufen, weil wir uns sozusagen in einer for-Schleife befinden, und folglich @* auch nur mit dem ersten Element aufgerufen wird. Ist Firma nicht das erste Attribut, bleibt es hier unbekannt. Will man ein Stylesheet schreiben, dass das oben gestellte Problem unabhängig von der Position des Attributs löst, dann braucht man eher sowas:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
<xsl:apply-templates select="/Projekte/Gruppe/Kollegen/Mitarbeiter | /Projekte/Gruppe/Ansprechpartner"/>
</xsl:template>
<xsl:template match="Mitarbeiter | Ansprechpartner">
<xsl:variable name="Name_des_Mitarbeiters"><xsl:value-of select="."/></xsl:variable>
<xsl:for-each select="./@*">

<xsl:if test="name()='Firma'">
Hallo <xsl:value-of select="$Name_des_Mitarbeiters"/> (<xsl:value-of select="name()"/> ist <xsl:value-of select="."/>)
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Wer testen will, ob es tatsächlich funktioniert, der muss die Datei Unternehmensberatung.xml, auf der alle Beispiele aufbauen, so modifizieren, dass das Attribut Firma nicht mehr an erster Stelle steht. Um die Vorgehensweise zu verstehen, muss man sehen, dass wir innerhalb von xsl:for-each keine Möglichkeit mehr haben, auf das Attribut zuzugreifen. Der Kontextknoten innerhalb von xsl:if ist der Attributknoten und nicht der Name des Mitarbeiters. Folglich müssen wir den Namen des Mitarbeiters an einer Stelle abgreifen, wo wir noch Zugriff haben, ihn dann in einer Variable sichern und ihn aus dieser Variablen bei Bedarf wieder rausfischen. Auf jeden Fall, haben wir jetzt xsl:if erlebt.

Eine Bedingung von mehreren ist richtig: xsl:choose

xsl:choose macht das, was bei Perl if in Verbindung mit elsif macht, respektive in anderen Programmiersprachen die case-Anweisung. Mit xsl:choose kann man mehrere Bedingungen setzten und für jede Bedingung isoliert festlegen, was geschehen soll, wenn die entsprechende Bedingung zutrifft. z.B. könnte man bei der Transformation wollen, dass der Ansprechpartner in rot und die normalen Mitarbeiter blau erscheinen. Das sieht dann so aus:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
<xsl:apply-templates select="/Projekte/Gruppe/Kollegen/Mitarbeiter | /Projekte/Gruppe/Ansprechpartner"/>
</xsl:template>

<xsl:template match="Mitarbeiter | Ansprechpartner">
<xsl:choose>
<xsl:when test="name()='Mitarbeiter'">
Hallo <font color="blue"><xsl:value-of select="."/></font>
</xsl:when>
<xsl:when test="name()='Ansprechpartner'">
Hallo <font color="red"><xsl:value-of select="."/></font>
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>

Funktionen zum Arbeiten mit Zeichenketten

Ausgefeilte Funktionnen zum Suchen und Bearbeiten von Zeichenketten gibt es in XSLT nicht. Das liegt wohl auch daran, dass man solche in der Regel nicht braucht. Ausgefeilte Funktionen zum Bearbeiten von Zeichenketten, wie etwa regular expression, braucht man eigentlich nur dann, wenn Texte nur sehr schwach strukturiert sind. Der Witz bei XML besteht aber gerade darin, dass sich sehr klar strukturieren lässt, die Daten also nie so chaotisch vorliegen. Einige Funktionen gibt es aber auch in XSLT, die werden wir nun kurz vorstellen.

Die Funktion string-length

Die Funktion string-length ermittelt die Länge einer Zeichenkette.
Wenn wir ermitteln wollen wieviele Buchstaben inklusiv Leerzeichen ein Zeichenketten hat, können wir sowas in der Art machen:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
<xsl:apply-templates select="/Projekte/Gruppe/Kollegen/Mitarbeiter"/>
</xsl:template>

<xsl:template match="Mitarbeiter">
Länge <xsl:value-of select="string-length(.)"/>
</xsl:template>
</xsl:stylesheet>


Will man die Länge des Knotennamens ermitteln, kann man sowas machen.

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
<xsl:apply-templates select="/Projekte/Gruppe/Kollegen/Mitarbeiter"/>
</xsl:template>

<xsl:template match="Mitarbeiter">
Länge <xsl:value-of select="string-length(name())"/>
</xsl:template>
</xsl:stylesheet>

Will man ermitteln, wieviele Buchstaben das Atrribut Firma hat, kann man so was machen:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
<xsl:apply-templates select="/Projekte/Gruppe/Kollegen/Mitarbeiter/attribute::Firma"/>
</xsl:template>

<xsl:template match="Mitarbeiter/attribute::Firma">
Länge <xsl:value-of select="string-length(.)"/>
</xsl:template>
</xsl:stylesheet>

Will man sich nur die Mitarbeiter anzeigen lassen, die mehr weniger als 16 Buchstaben haben, kann man das so machen:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">

<xsl:apply-templates select="/Projekte/Gruppe/Kollegen/Mitarbeiter"/>
</xsl:template>

<xsl:template match="Mitarbeiter">
<xsl:if test="string-length(.)&lt;='15'">
Name <xsl:value-of select="."/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>

Wir erhalten

C:\saxon2>saxon Unternehmensberatung.xml test.xsl
<?xml version="1.0" encoding="utf-8"?>
Name Werner Lepinski
Name Erika Saufwech
Name Hans Geldfliech
Name Werner Nordflut
Name Peter Wessnich
C:\saxon2>

Wie deutlich zu erkennen, muss das &lt;= anstelle von <= stehen bzw. &lt; = anstelle von >= stehen. Im übrigen sind die üblichen Operatoren gültig. Will man z.B. alle Mitarbeiter sehen, die nicht exakt 15 Zeichen haben, kann man sowas machen:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">

<xsl:apply-templates select="/Projekte/Gruppe/Kollegen/Mitarbeiter"/>
</xsl:template>

<xsl:template match="Mitarbeiter">
<xsl:if test="string-length(.)!='15'">
Name <xsl:value-of select="."/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>

Man erhält dann so was:

C:\saxon2>saxon Unternehmensberatung.xml test.xsl
<?xml version="1.0" encoding="utf-8"?>
Name Erika Saufwech
Name Marina Meimportauncarajo
Name Peter Wessnich
C:\saxon2>

Die Funktion concat

Mit concat lassen sich Zeichenketten zu einer grossen Zeichenkette verbinden, das sieht dann so aus:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:apply-templates select="/Projekte/Gruppe/Kollegen/Mitarbeiter"/>
</xsl:template>
<xsl:template match="Kollegen/Mitarbeiter">
Hallo <xsl:value-of select="concat(node(),' Firma ',@Firma)"/>
</xsl:template>
</xsl:stylesheet>

Die Funktion contains

Mit der Funktion contains kann man überprüfen, ob eine Zeichenkette in einer anderen enthalten ist. Mit contains können wir uns z.B. alle Mitarbeiter anzeigen lassen, die als Vornamen Werner haben (Werner Lepinski und Werner Nordflut).

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">

<xsl:apply-templates select="/Projekte/Gruppe/Kollegen/Mitarbeiter"/>
</xsl:template>

<xsl:template match="Kollegen/Mitarbeiter">
<xsl:if test="contains(node(),'Werner')">
Hallo <xsl:value-of select="."/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>

Die Funktion start-with

Mit der Funktion star-with kan man prüfen, ob eine Zeichenkette mit einer bestimmten Zeichenkette beginnt. Wollen wir z.B. alle Mitarbeiter, deren Namen mit P anfängt (Peter Wessnich) dann können wir sowas machen:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">

<xsl:apply-templates select="/Projekte/Gruppe/Kollegen/Mitarbeiter"/>
</xsl:template>

<xsl:template match="Kollegen/Mitarbeiter">
<xsl:if test="starts-with(node(),'P')">
Hallo <xsl:value-of select="."/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>

Die Funktion substring

Mit der Funktion substring kann man Teilzeichenketten aus einer Zeichenkette rausschneiden. Die wohl in alle Programmiersprachen verfügbare Funktion substring gibt es auch in XSLT. Wollen wir z.B. aus den Namen der Mitarbeiter immer den Bereich zwischen dem fünften und dem fünfzehnten Buchstaben rausschneiden, können wir sowas machen:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">

<xsl:apply-templates select="/Projekte/Gruppe/Kollegen/Mitarbeiter"/>
</xsl:template>

<xsl:template match="Kollegen/Mitarbeiter">
Hallo <xsl:value-of select="substring(node(),5,10)"/>
</xsl:template>
</xsl:stylesheet>

Wir übergeben also an substring drei Parameter, die Zeichenkette selbst, die wir und in diesem Falle über node() rausfischen, den Startpunkt, ab dem wir rausschneiden wollen und die Anzahl der Buchstaben, die wir rausschneiden wollen. Wir erhalten dann das:

C:\saxon2>saxon Unternehmensberatung.xml test.xsl
<?xml version="1.0" encoding="utf-8"?>
Hallo er Lepinsk
Hallo a Saufwech
Hallo Geldfliec
Hallo er Nordflu
Hallo na Meimpor
Hallo r Wessnich
C:\saxon2>

Die Funktionen substring-before und substring-after

Mit der Funktionen substring-before und substring-after kann man rausfischen was vor, bzw. nach einer bestimmten Zeichenkette steht. Interessiert man sich z.B. für die Nachnamen und hat diese so abgespeichert wie in diesem Beispiel, ungeschickt aber didaktisch wertvoll, dann könnte man sich die Vornamen über substring-before wieder rausfischen. Man könnte nach dem Leerzeichen suchen und sich alles vor dem Leerzeichen zeigen lassen, was ja dann in den hier zugrunde liegenden Beispielen der Vorname ist:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">

<xsl:apply-templates select="/Projekte/Gruppe/Kollegen/Mitarbeiter"/>
</xsl:template>

<xsl:template match="Kollegen/Mitarbeiter">
Hallo <xsl:value-of select="substring-before(node(),' ')"/>
</xsl:template>
</xsl:stylesheet>

Wir erhalten

C:\saxon2>saxon Unternehmensberatung.xml test.xsl
<?xml version="1.0" encoding="utf-8"?>
Hallo Werner
Hallo Erika
Hallo Hans
Hallo Werner
Hallo Marina
Hallo Peter
C:\saxon2>

Umgekehrt, umgekehrt. Wollen wir den Nachname haben, nehmen wir wieder das Leerzeichen und schauen, was danach kommt:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">

<xsl:apply-templates select="/Projekte/Gruppe/Kollegen/Mitarbeiter"/>
</xsl:template>

<xsl:template match="Kollegen/Mitarbeiter">
Hallo <xsl:value-of select="substring-after(node(),' ')"/>
</xsl:template>
</xsl:stylesheet>

Wir erhalten

C:\saxon2>saxon Unternehmensberatung.xml test.xsl
<?xml version="1.0" encoding="utf-8"?>
Hallo Lepinski
Hallo Saufwech
Hallo Geldfliech
Hallo Nordflut
Hallo Meimportauncarajo
Hallo Wessnich
C:\saxon2>

Anzahl der Knoten ermitteln

Will man z.B. wissen, wieviele Mitarbeiter es gibt, kann man sowas in der Art machen:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:value-of select="count(/Projekte/Gruppe/Kollegen/Mitarbeiter)"/>
</xsl:template>
</xsl:stylesheet>

Den letzten Knoten ermitteln

Will man den letzten Mitarbeiter in der zweiten Gruppe ermitteln, kann man das so machen:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
<xsl:value-of select="/Projekte/Gruppe/Kollegen/Mitarbeiter[last()]"/>
</xsl:template>
</xsl:stylesheet>

X-beliebigen Knoten ermitteln

Will man irgendeinen Knoten ermitteln, von dem man zumindest weiss, welche Nummer er hat, kann man sowas machen:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
<xsl:value-of select="/Projekte/Gruppe/Kollegen/Mitarbeiter[position()=2]"/>
</xsl:template>

</xsl:stylesheet>

Auf gleichnamige Elemente zugreifen, die in unterschiedlichen Knoten sind

Den Ansprechpartner haben wir in den zwei Gruppen und in Team. Damit ist klar, dass wir auf alle Ansprechpartner mit der XPATH-Formulierung /Projekte/Gruppe/Ansprechpartner nicht zugreifen können, da einer ja in Team sitzt. Dieses Problem lässt sich folgendermassen lösen:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
<xsl:for-each select="/Projekte/child::*/Ansprechpartner">
Hallo <xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>

</xsl:stylesheet>

Mit child::* selektieren wir alle Knoten dieser Hierarchiestufe, in unserem Falle also sowohl Gruppe als auch Team.

vorhergehendes Kapitel