Werbung einblenden Werbung ausblenden


Home / Tutorials / xml, xsl, xpath Handbuch / Abfragen mit XPATH


Abfragen mit XPATH
Relative und absolute Pfade
XPATH Achsen
Die Achse ancestor
Die Ache ancestor-or-self
Die Aches descendant
Die Achse descendant-or-self
Die Achse following
Die Achse following-sibling
Die Achse preceding
Die Achse preceding-sibling
Präziserer Zugriff mit position und last
Auf bestimmte Elemente innerhalb einer Achse zugreifen
Arbeitem mit Prädikaten
Gleichnamige Elemente finden, die auf unterschiedlichen Hierarchiestufen liegen
or in einem XPATH Ausdruck
Zeichenkettenfunktionen
Verbinden von Zeichenketten: concat()
Überprüfen, ob ein Zeichenkette Bestandteil einer anderen Zeichenkette ist
Die Länge von Zeichenketten ermitteln:string-length()
Testen, ob eine Zeichenkette mit einer bestimmten Zeichenkette beginnt
Zeichenketten aus einer Zeichenkette rausschneiden: substring()
Alle Zeichen vor bzw. nach einem bestimmten Zeichen rausfischen: substring-before() und substring-after()
Funktionen zum Ermitteln von Knoteneigenschaften
Ermitteln des letzten Knotens, last()
Die Funktion count()

Abfragen mit XPATH

XPATH ist, wenn man will, das sql für XML Dokumente. Mit XPATH kann auf beliebige Knoten eines XML Dokumentes zugegriffen werden. XPATH ist die Abfragesprache von XSLT, wird aber von verschiedenen Parsern unterstützt, die eigentlich auf den DOM Standard aufsetzen. Um die Möglichkeiten von XPATH aufzuzeigen, gehen wir von dem XML Dokument aus, dass schon dem ganzen Handbuch zugrunde liegt.

<?xml version="1.0" encoding="ISO-8859-1"?>
<Projekte>
<Gruppe>
<Gruppenname stand="abgeschifft">Berliner Verwaltungsreform</Gruppenname>
<Kollegen>
<Mitarbeiter Summe="90000" Firma="Preis Wasserhaus">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>
<Mitarbeiter>Werner Bummerang</Mitarbeiter>
<Ansprechpartner>Werner Kostfix</Ansprechpartner>
<Telefon>030-4544332</Telefon>
</Team>
</Projekte>

Um XPATH in Aktion zu zeigen, brauchen wir des weiteren einen Ansatz, der XPATH verwendet. Der hinsichtlich Implementierung einfachste Ansatz ist XSLT mit dem Saxon Prozessor. Für Details siehe Auslesen eines XML Dokumentes mit XSLT. Diesen verwenden wir. Wer sehen will, wie man XPATH auch bei Verwendung des DOM Ansatzes verwendet, kann zu dem Kapitel Auslesen einer XML Datei mit dem Perl Modul XML::LIBXML gehen. Eine grundlegende Ahnung von XSLT, siehe Auslesen eines XML Dokumentes mit XSLT, ist sinnvoll. Um den Wurzelknoten abzugreifen geben wir einfach einen Slash ein.

<?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="name(node())"/>
</xsl:template>
</xsl:stylesheet>

Kopieren wir dieses Stylesheet und die dazugehörige XML Datei in den Ordner wo auch die saxon.exe liegt und geben dann

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

So erhalten wir als Ergebnis Projekte. Mit der Funktion name() können wir uns den Namen des als Parameter übergebenen Knotens anschauen. node() ermittelt den aktuellen Knoten. Den aktuellen Knoten ermittelt aber auch der schnöde Punkt, so dass wir auch sowas hätten schreiben 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="/Projekte">
<xsl:value-of select="name(.)"/>
</xsl:template>
</xsl:stylesheet>

Da die Funktion name() aber eh im Default den Kontextknoten zeigt, hätte man auch sowas schreiben 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="/Projekte">
<xsl:value-of select="name()"/>
</xsl:template>
</xsl:stylesheet>

Alle drei Varianten liefern Projekte, also den aktuellen Knoten.

Relative und absolute Pfade

Ein absoluter Pfad beginnt mit einem Slash. Das hatten wir oben. Ein absoluter Pfad ist ein Pfad, der an der Wurzel startet. Relative Pfade starten beim aktuellen Kontextknoten.

<?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">
<xsl:apply-templates select="Gruppe"/>
</xsl:template>
<xsl:template match="Gruppe">
<xsl:value-of select="name()"/>
</xsl:template>
</xsl:stylesheet

Wir erhalten zweimal Gruppe, weil es zwei Elemente Gruppe gibt und foglich das Template Gruppe zweimal aufgerufen wird.

XPATH Achsen

Will man alle Mitarbeiter sehen, könnte man das, wie bereits oben beschrieben, so machen. Allerdings würden so nur die Mitarbeiter im Element Gruppe erfasst.

<?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">
<xsl:apply-templates select="Gruppe/Kollegen/Mitarbeiter"/>
</xsl:template>
<xsl:template match="Mitarbeiter">
<xsl:value-of select="name()"/>
</xsl:template>
</xsl:stylesheet>

Alternativ, und manchmal ist das sinnvoll, könnte man es auch so machen. Bei dieser Methode werden alle Mitarbeiter erfasst, auch die im Element Team.

<?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">
<xsl:apply-templates select="Gruppe/Kollegen/child::*"/>
</xsl:template>
<xsl:template match="child::*">
<xsl:value-of select="name()"/>
</xsl:template>
</xsl:stylesheet>

Wir erhalten wieder 6 Mal Mitarbeiter. Mit Achsen kann man von ausgehend vom aktuellen Knoten nach rechts, links, oben und unten wandern.

Die Achse ancestor

Mit der Achse ancestor holen wir, ausgehend von dem Kontextknoten, alle Elemente bis zum Wurzelknoten.

<?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">
<xsl:apply-templates select="Team/Ansprechpartner"/>
</xsl:template>
<xsl:template match="Ansprechpartner">
<xsl:for-each select="ancestor::*">
<xsl:value-of select="name()"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Wir erhalten Projekte Team, weil das der Opa und der Vater des aktuellen Knotens Ansprechpartner in Team ist.

Die Ache ancestor-or-self

Die Achse ancestor-or-self ist mit der Achse ancestor weitgehend identisch, der einzige Unterschied besteht darin, dass ancestor-or-self auch den Kontextknoten selber mit erfasst.

<?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">
<xsl:apply-templates select="Team/Ansprechpartner"/>
</xsl:template>
<xsl:template match="Ansprechpartner">
<xsl:for-each select="ancestor-or-self::*">
<xsl:value-of select="name()"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Wir erhalten Projekte Team Ansprechpartner.Der Stern * steht hier für alle Elemente.

Die Aches descendant

Mit der Achse descendant kann man alle Knoten unterhalb des Kontextknotens erfassen.

<?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">
<xsl:apply-templates select="Team"/>
</xsl:template>
<xsl:template match="Team">
<xsl:for-each select="descendant::*">
<xsl:value-of select="name()"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Wir erhalten Name Ansprechpartner Telefon, weil diese Unterhalb von Team liegen.

Die Achse descendant-or-self

Die Achse descendant-or-self erfasst alle direkten Kindknoten und den Kontextknoten.

<?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">
<xsl:apply-templates select="Team"/>
</xsl:template>
<xsl:template match="Team">
<xsl:for-each select="descendant-or-self::*">
<xsl:value-of select="name()"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Wir erhalten Team Name Ansprechpartner Telefon

Die Achse following

Die Achse following erfasst alle Knoten rechts vom Kontextknoten und die Kindknoten dieser Knoten.

<?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">
<xsl:apply-templates select="Gruppe[1]"/>
</xsl:template>
<xsl:template match="Gruppe[1]">
<xsl:for-each select="following::*">
Name <xsl:value-of select="name()"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Wir erhalten

C:\saxon2>saxon Unternehmensberatung.xml test.xsl
<?xml version="1.0" encoding="utf-8"?>
Name Gruppe
Name Gruppenname
Name Kollegen
Name Mitarbeiter
Name Mitarbeiter
Name Mitarbeiter
Name Ansprechpartner
Name Adresse
Name Strasse
Name Ort
Name Kostenvoranschlag
Name Team
Name Name
Name Ansprechpartner
Name Telefon
C:\saxon2>

Wir sehen dass wir die Gruppe erhalten, das ist der Knoten rechts des Kontextknotens und alle Kindknoten. Weiter erhalten wir auch den Schwesternknoten Team und dessen Kindknoten.

Die Achse following-sibling

Die Achse following-sibling erfasst ebenfalls die Schwesterknoten rechts vom Kontextknoten, allerdings ohne deren Kindknoten.

<?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">
<xsl:apply-templates select="Gruppe[1]"/>
</xsl:template>
<xsl:template match="Gruppe[1]">
<xsl:for-each select="following-sibling::*">
<xsl:value-of select="name()"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Wir erhalten Gruppe Team.

Die Achse preceding

Die Achse preceding liefert alle Schwesternknoten links vom Kontextknoten und 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="/Projekte">
<xsl:apply-templates select="Team"/>
</xsl:template>
<xsl:template match="Team">
<xsl:for-each select="preceding::*">
Name <xsl:value-of select="name()"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Wir erhalten

C:\saxon2>saxon Unternehmensberatung.xml test.xsl
<?xml version="1.0" encoding="utf-8"?>
Name Gruppe
Name Gruppenname
Name Kollegen
Name Mitarbeiter
Name Mitarbeiter
Name Mitarbeiter
Name Ansprechpartner
Name Adresse
Name Strasse
Name Ort
Name Budget
Name Kommentar
Name Gruppe
Name Gruppenname
Name Kollegen
Name Mitarbeiter
Name Mitarbeiter
Name Mitarbeiter
Name Ansprechpartner
Name Adresse
Name Strasse
Name Ort
Name Kostenvoranschlag
C:\saxon2>

Die Achse preceding-sibling

Die Achse preceding-sibling erfasst alle Schwesternknoten links vom Kontextknoten allerdings ohne deren Kindknoten.

<?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">
<xsl:apply-templates select="Team"/>
</xsl:template>
<xsl:template match="Team">
<xsl:for-each select="preceding-sibling::*">
<xsl:value-of select="name()"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Wir erhalten Gruppe Gruppe.

Präziserer Zugriff mit position und last

Mit preceding, preceding-sibling, descendant, descendant-sibling, following, following-sibling und ancestor bzw. ancestor-self haben wir immer nur eine ganze Gruppe von Knoten erhalten. Was ist, wenn man nur den ersten Schwesternknoten rechts, links, oberhalb oder unterhalb des Kontextknotens haben will ? Dies kann man erreichen mit position.

Schwersternknoten und dessen Kindknoten unmittelbar rechts vom Kontextknoten erfassen
Wenn die erste Gruppe der Kontextknoten ist, und wir die zweite Gruppe erfassen wollen, 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="/Projekte">
<xsl:apply-templates select="Gruppe[1]"/>
</xsl:template>
<xsl:template match="Gruppe[1]">

<xsl:for-each select="following-sibling::*[position()=1]">
<xsl:for-each select="descendant::*">
Name <xsl:value-of select="name()"/>
</xsl:for-each>
</xsl:for-each>

</xsl:template>
</xsl:stylesheet>

Wir erhalten sowas und das ist korrekt.

C:\saxon2>saxon Unternehmensberatung.xml test.xsl
<?xml version="1.0" encoding="utf-8"?>
Name Gruppenname
Name Kollegen
Name Mitarbeiter
Name Mitarbeiter
Name Mitarbeiter
Name Ansprechpartner
Name Adresse
Name Strasse
Name Ort
Name Kostenvoranschlag
C:\saxon2>

Schwierig einzusehen sind hierbei die verschachtelten for-each Schleifen. Mit following-sibling::*[position()=1] erfassen wir den unmittelbar rechts folgenden Schwesternknoten, also die zweite Gruppe. Die zweite for-each Schleife geht von diesem Kontextknoten aus und erfasst mit descendant::* alle Kindsknoten dieses Schwesternknoten. Innerhalb dieser zweiten for-each Schleife lassen wir uns dann alle Kindknoten zeigen. Hätten wir das Team erfassen wollen, hätten wir statt following-sibling::*[postion()=1] eben following-sibling::*[postion()=2] geschrieben etc.

Den letzten Schwesternknoten und dessen Kindknoten erfassen
Will man den letzten Schwesternknoten erfassen, 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="/Projekte">
<xsl:apply-templates select="Gruppe[1]"/>
</xsl:template>
<xsl:template match="Gruppe[1]">
<xsl:for-each select="following-sibling::*[last()]">
<xsl:for-each select="descendant::*">
Name <xsl:value-of select="name()"/>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Wir erhalten sowas, was tatsächlich das Element Team wiederspiegelt.

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

Auf bestimmte Elemente innerhalb einer Achse zugreifen

Wenn man weiss, wie das Element heisst, auf dass man zugreifen will, kann man auch über eine Achse direkt auf das Element zugreifen. Nehmen wir mal an wir suchen zum Ansprechpartner im Element Team die Telefonnummer. Dann können wir auch sowas machen.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/Projekte">
<xsl:apply-templates select="Team/Ansprechpartner"/>
</xsl:template>
<xsl:template match="Ansprechpartner">
<xsl:for-each select="following-sibling::Telefon">
Telefon <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"?>
Telefon 030-4544332
C:\saxon2>

Was dem entpricht, was wir uns wünschen. Die Auswahl bestimmter Knoten auf einer Achse bezeichnet man als Knotentest.

Arbeitem mit Prädikaten

Will man noch feiner selektieren, also z.B. auf einer Achse einen Knoten ermitteln, der weiteren Kriterien entspricht, kann man das mit Attributen machen. Wir können z.B. vom Kontextknoten Gruppe[1]/Kollegen starten, dann die Achse descendant entlangwandern, was uns ja die Mitarbeiter liefert, aber von diesen nur jene selektieren, die das Attribut Firma besitzen. Das sieht dann so aus.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/Projekte">
<xsl:apply-templates select="Gruppe[1]/Kollegen"/>
</xsl:template>
<xsl:template match="Kollegen">
<xsl:for-each select="descendant::*[attribute::Firma]">
Mitarbeiter <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"?>
Mitarbeiter Werner Lepinski
Mitarbeiter Erika Saufwech
C:\saxon2>

Und das ist was wir uns erhofft hatten. In der ersten Gruppe haben die zwei Mitarbeiter Werner Lepinski und Erika Saufwech das Attribut Firma. Für attribute::irgendwas gibt es noch eine Kurzschreibweise, die sieht so aus.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/Projekte">
<xsl:apply-templates select="Gruppe[1]/Kollegen"/>
</xsl:template>
<xsl:template match="Kollegen">
<xsl:for-each select="descendant::*[@Firma]">
Mitarbeiter <xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Man könnte noch präziser selektieren, etwa nur die Mitarbeiter rausfischen, die bei Preis Wasserhaus beschäftigt sind, also nur den Werner Lepinski. Das sieht dann so aus.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/Projekte">
<xsl:apply-templates select="Gruppe[1]/Kollegen"/>
</xsl:template>
<xsl:template match="Kollegen">
<xsl:for-each select="descendant::*[@Firma='Preis Wasserhaus']">
Mitarbeiter <xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Wir erhalten Mitarbeiter Werner Lepinski, was richtig ist, da er in dieser Gruppe der einzige ist, der bei Preis Wasserhaus beschäftigt ist. Wir können noch präziser selektieren, wenn wir mehrere Prädikate über and verknüpfen. Zum Beispiel können wir uns alle Mitarbeiter anzeigen lassen, die als Attribut Werner Lepinski haben und als status ausgeliehen, also den Peter Wessnich.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/Projekte">
<xsl:apply-templates select="child::*/Kollegen"/>
</xsl:template>
<xsl:template match="Kollegen">
<xsl:for-each select="descendant::*[@Firma='Preis Wasserhaus' and @status='ausgeliehen']">
Mitarbeiter <xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Das liefert uns dann den Peter Wessnich. Selbsverständlich funktionniert auch or (oder). Wollen wir z.B. alle Mitarbeiter haben, die als Wert für das Attribut Preis Wasserhaus oder Wertarbeit haben, können wir sowas machen.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/Projekte">
<xsl:apply-templates select="child::*/Kollegen"/>
</xsl:template>
<xsl:template match="Kollegen">
<xsl:for-each select="descendant::*[@Firma='Preis Wasserhaus' or @Firma='Wertarbeit']">
Mitarbeiter <xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Wir erhalten alle Mitarbeiter, die entweder bei Preis Wasserhaus oder Wertarbeit beschäftigt sind. Nach einem ähnlichen Schema wäre es auch möglich gewesen, nur die Gruppe rauszufischen, die das Kindelement Kostenvoranschlag besitzt, was ja nur bei der zweiten Gruppe der Fall ist.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/Projekte">
<xsl:value-of select="(Gruppe[Kostenvoranschlag])"/>
</xsl:template>

</xsl:stylesheet>

Als Ergebnis dieses Stylesheets erhalten wir die Textelemente der zweiten Gruppe, den nur diese hat das Element Kostenvoranschlag.

C:\saxon2>saxon Unternehmensberatung.xml test.xsl
<?xml version="1.0" encoding="utf-8"?>
Hamburger Verwaltungschaos
Werner Nordflut
Marina Meimportauncarajo
Peter Wessnich
Ludwig Noresponsable
An der Waterkant 15
45555 Hamburg
30 000000
C:\saxon2>

Man kann das, ähnlich wie bei Attribut, noch weiter präzisieren, indem man auch noch angibt, welchen Textknoten das Element haben soll.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/Projekte">
<xsl:value-of select="(Gruppe[Kostenvoranschlag='30 000000'])"/>
</xsl:template>
</xsl:stylesheet>

Das Ergebnis ist dann das gleiche wie oben, da wir nur einen Kostenvoranschlag haben. Ist das Attribut eine Zahl, lassen sich auch die üblichen mathematischen Operatoren anwenden. z.B. könnte man alle Mitarbeiter ermitteln, die bei Summe mehr als 30000 haben.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/Projekte">
<xsl:for-each select="Gruppe/Kollegen/descendant::*[@Summe &lt; '30000']">
Hallo <xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Das Ergebnis sieht dann so aus.

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


Das mathematische größer Zeichen kann nicht verwendet werden, anstatt dessen ist &gt;
zu verwenden (die dem > Zeichen entsprechende HTML entity). Mit derselben Methode kann man sich auch alle Mitarbeiter anzeigen lassen, die bei Summe weniger als 3000 haben.


<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/Projekte">
<xsl:for-each select="Gruppe/Kollegen/descendant::*[@Summe &lt; '30000']">
Hallo <xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Wir erhalten dann die Erika Saufwech und den Hans Geldfliech.

Gleichnamige Elemente finden, die auf unterschiedlichen Hierarchiestufen liegen

Wenn man alle gleichnamigen Elemente finden will und diese auf unterschiedlichen Hierarchiestufen liegen, lässt sich schlecht ein XPATH Ausdruck formulieren, da dieser ja immer den ganzen Pfad beschreibt, genau dieser ist aber dann unterschiedlich ist. In unserem Beispiel haben wir z.B. auch einen Mitarbeiter in Team, der ist aber eine Hierarchiestufe weiter oben als die Mitarbeiter im Element Gruppe, weil er nicht in einem Element Kollegen gekapselt ist. Will man jetzt alle Mitarbeiter rausfischen, kann man sowas machen.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/Projekte">
<xsl:apply-templates select='//Mitarbeiter'/>
</xsl:template>
<xsl:template match="Mitarbeiter">
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>

Das gleiche geht natürlich auch mit Attributen.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/Projekte">
<xsl:apply-templates select='//@Firma'/>
</xsl:template>
<xsl:template match="@Firma">
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>

Das liefert uns dann alle Firmen.

or in einem XPATH Ausdruck

Wir hätten das Problem oben auch, wenn auch umständlicher, dadurch lösen können, dass wir zwei Pfade definieren. Das hätte dann so ausgesehen.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/Projekte">
<xsl:apply-templates select='Gruppe/Kollegen/Mitarbeiter | Team/Mitarbeiter'/>
</xsl:template>
<xsl:template match="Mitarbeiter">
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>

Bei dieser Variante definieren wir jeweils den kompletten Pfad zu jedem Mitarbeiter.

Zeichenkettenfunktionen

XPATH kennt manche der in anderen Programmiersprachen üblichen Funktionen zur Bearbeitung und Analyse von Zeichenketten. Es ist wohl damit zu rechnen, dass irgendwann einmal auch regular expressions unterstützt werden.

Verbinden von Zeichenketten: concat()

Mit concat lassen sich Zeichenketten verknüpfen.

<?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">
<xsl:apply-templates select='Gruppe/Kollegen/Mitarbeiter'/>
</xsl:template>
<xsl:template match="Mitarbeiter">
Herr/Frau <xsl:value-of select="concat(node(),' arbeitet bei ',@Firma,' Status ',@status)"/>
</xsl:template>
</xsl:stylesheet>

In der Regel dürfte die concat Funktion nicht viel bringen, das gleiche hätte man auch so erreichen 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="/Projekte">
<xsl:apply-templates select='Gruppe/Kollegen/Mitarbeiter'/>
</xsl:template>
<xsl:template match="Mitarbeiter">
Herr/Frau <xsl:value-of select="node()"/> arbeitet bei <xsl:value-of select="@Firma"/> Status <xsl:value-of select="@status"/>
</xsl:template>
</xsl:stylesheet>

Überprüfen, ob ein Zeichenkette Bestandteil einer anderen Zeichenkette ist

Wenn wir alle Namen rausfischen wollen, die Werner enthalten, also Werner Lepinski und Werner Nordflut, 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="/Projekte">
<xsl:apply-templates select='Gruppe/Kollegen/Mitarbeiter'/>
</xsl:template>
<xsl:template match="Mitarbeiter">
Wert <xsl:value-of select="contains(node(),'Werner')"/>
</xsl:template>
</xsl:stylesheet>

Wir erhalten

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

Fazit, die Funktion liefert true zurück, wenn die Zeichenkette enthalten ist und false, wenn dies nicht der Fall ist. Das kann man dann in einer if clause ausnützen.

<?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">
<xsl:apply-templates select='Gruppe/Kollegen/Mitarbeiter'/>
</xsl:template>
<xsl:template match="Mitarbeiter">
<xsl:if test="contains(node(),'Werner')='true'">
Hallo <xsl:value-of select="."/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>

Die Länge von Zeichenketten ermitteln:string-length()

Will man die Länge einer Zeichenkette 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="/Projekte">
<xsl:apply-templates select='Gruppe/Kollegen/Mitarbeiter'/>
</xsl:template>
<xsl:template match="Mitarbeiter">
Wert <xsl:value-of select="string-length(.)"/>
</xsl:template>
</xsl:stylesheet>

Testen, ob eine Zeichenkette mit einer bestimmten Zeichenkette beginnt

Will man z.B. testen, ob ein Name mit dem Buchstaben P beginnt, was bei einem Mitarbeiter, dem Peter Wessnich ja der Fall ist, dann 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">
<xsl:apply-templates select='Gruppe/Kollegen/Mitarbeiter'/>
</xsl:template>
<xsl:template match="Mitarbeiter">
Wert <xsl:value-of select="starts-with(node(),'P')"/>
</xsl:template>
</xsl:stylesheet>

Wir erhalten dann

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

Was wir über eine if Bedingung wie oben beschrieben ausnützen können.

Zeichenketten aus einer Zeichenkette rausschneiden: substring()

Mit der Funktion substring können wir aus einer bestimmten Zeichenkette einen Teil herausschneiden.

<?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">
<xsl:apply-templates select='Gruppe/Kollegen/Mitarbeiter'/>
</xsl:template>
<xsl:template match="Mitarbeiter">
Ergebnis <xsl:value-of select="substring(node(),5,6)"/>
</xsl:template>
</xsl:stylesheet>

Wir fischen also vom aktuellen Knoten ab der Position 5 die nächsten 6 Zeichen raus. Das Ergebnis sieht dann so aus.

C:\saxon2>saxon Unternehmensberatung.xml test.xsl
<?xml version="1.0" encoding="utf-8"?>
Ergebnis er Lep
Ergebnis a Sauf
Ergebnis Geldf
Ergebnis er Nor
Ergebnis na Mei
Ergebnis r Wess
C:\saxon2>

Alle Zeichen vor bzw. nach einem bestimmten Zeichen rausfischen:
substring-before() und substring-after()

Wenn wir uns alle Vornamen rausfischen wollen, können wir bei dem Leerzeichen die Zeichenkette aufspalten und das was davor kommt rausfischen.

<?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">
<xsl:apply-templates select='Gruppe/Kollegen/Mitarbeiter'/>
</xsl:template>
<xsl:template match="Mitarbeiter">
Ergebnis <xsl:value-of select="substring-before(node(),' ')"/>
</xsl:template>
</xsl:stylesheet>

Das Ergebnis sieht dann so aus.

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

Funktionen zum Ermitteln von Knoteneigenschaften

Ermitteln, wieviele Knoten eines bestimmten Typs es überhaupt gibt. count()
Interessiert man sich dafür, wieviele Mitarbeiter es gibt, 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">
<xsl:value-of select='count(//Mitarbeiter)'/>
</xsl:template>
</xsl:stylesheet>

Das Ergebnis ist dann sieben.

Ermitteln des letzten Knotens, last()

Die Funktion last() ermittelt die Postitionsnummer des letzten Knotens der aktuellen Knotenmenge. Das heisst, dass sie wohl sinnvoll nur innerhalb eines Pradikates mit position, also z.B. descendant::*[position=last()] eingesetzt werden kann. Man kann ihr keine Parameter übergeben, also sie kann nur die Positionsnummer des letzten Knotens der aktuellen Knotenmenge ermitteln.

<?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">
<xsl:apply-templates select="//Kollegen"/>
</xsl:template>
<xsl:template match="Kollegen">
Wert <xsl:value-of select="last()"/>
</xsl:template>
</xsl:stylesheet>

Das Resultat sieht dann so aus.

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

Da es zwei Kollegen gibt, wird das Template Kollegen zweimal aufgerufen. last() ermittelt dann jeweils die Position des letzten Knotens der Knotenmenge Kollegen. Ein sinnvolles Beispiel 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">
<xsl:template match="/">
<xsl:apply-templates select="/Projekte/Gruppe"/>
</xsl:template>
<xsl:template match="Gruppe">
Hallo <xsl:value-of select="Kollegen/Mitarbeiter[last()]"/>
</xsl:template>
</xsl:stylesheet>

Wie das erste, weniger sinnvolle Beispiel gezeigt hat, ermittelt die Funktion last() das letzte Element einer Knotenmenge.

Die Funktion count()

Die Funktion count() unterscheidet sich hiervon in zwei Aspekten. Erstens kann man ihr eine Knotenmenge als Parameter übergeben und zweitens ermittelt sie die Anzahl der Elemente dieser Knotenmenge, ermittelt also den letzten Knoten der Knotenmenge, die sie als Parameter übergeben bekommt.

<?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">
<xsl:apply-templates select="//Kollegen"/>
</xsl:template>
<xsl:template match="Kollegen">
Wert <xsl:value-of select="count(descendant::*)"/>
</xsl:template>
</xsl:stylesheet>

Wir erhalten

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

vorhergehendes Kapitel