Bedingungscode mit if-Ausdrücken verkleinern

(Auszug aus "XSLT Kochbuch" von Sal Mangano)

Problem

Ihr komplexer XSLT-Code ist aufgrund des großen XML-Overheads zu umfangreich, wenn Sie einfache If-then-else-Bedingungen ausdrücken wollen.

Lösung

XPath 1.0

Es gibt einige Tricks, die Sie in XPath 1.0 anwenden können, um in einfachen Situationen auf den Einsatz des ausführlichen xsl:choose von XSLT zu verzichten. Diese Tricks beruhen auf der Tatsache, dass in einem mathematischen Kontext false zu 0 und true zu 1 konvertiert wird.

Daher können z.B. die Minimal-, Maximal- und Absolut-Werte in XPath 1.0 direkt berechnet werden. In diesen Beispielen nehmen wir an, dass $x und $y Integer enthalten.

(: min :)

($x <= $y) * $x + ($y < $x) * $y

(: max :)

($x >= $y) * $x + ($y > $x) * $y

(: abs :)

(1 - 2 * ($x < 0)) * $x

XPath 2.0

Für die einfachen Fälle im XPath 1.0-Abschnitt (min, max, abs) gibt es nun integrierte XPath-Funktionen. Für andere einfache Bedingungen verwenden Sie den neuen Bedingungsausdruck if.

(: Der Wert eines fehlenden Attributs wird standardmäßig auf 10 gesetzt. :)

if (@x) then @x else 10

(: Der Wert eines fehlenden Elements wird standardmäßig auf 'unauthorized' gesetzt. :)

if (password) then password else 'unauthorized'

(: Schutz vor der Division durch null. :)

if ($d ne 0) then $x div $d else 0

(: Ein para-Element, wenn es wenigstens ein Zeichen enthält, das kein Leerraum ist; ansonsten ein einzelnes Leerzeichen. :)

if (normalize-space(para)) then string(para) else ' '

Diskussion

Falls Sie schon lange XSLT 1.0 programmieren, zucken Sie wahrscheinlich jedes Mal zusammen, wenn Sie einem Template Bedingungscode hinzufügen müssen. Bei mir ist es zumindest so, und ich versuche oft fieberhaft, die XSLT-Mustererkennungskonstrukte auszuschöpfen, um Bedingungscode zu minimieren. Dies liegt nicht daran, dass dieser Code in XSLT komplizierter oder weniger effizient wäre, sondern daran, dass er so schrecklich langatmig ist. Ein einfaches xsl:if ist nicht so schlimm, aber wenn Sie If-then-else-Logik ausdrücken wollen, sind Sie nun gezwungen, das sperrigere xsl:choose zu verwenden. Örks!

In XSLT 2.0 gibt es eine Alternative, die wird aber eigentlich in XPath 2.0 richtig geliefert, anstatt in XSLT 2.0. Auf den ersten Blick könnte man den Eindruck gewinnen, dass XPath durch die Einführung der – von prozeduralen Programmierern so genannten – Anweisungen zur Ablaufsteuerung in gewisser Weise verfälscht wurde. Sobald Sie jedoch damit beginnen, XPath 2.0 in seiner vollen Pracht einzusetzen, werden Sie schnell bemerken, dass sowohl XPath als auch XSLT durch diese Erweiterungen verbessert worden sind. Darüber hinaus wird durch den Bedingungsausdruck in XPath 2.0 das Element xsl:if nicht abgelehnt, sondern es wird die Notwendigkeit reduziert, es in Fällen einzusetzen, in denen es am schwierigsten ist. Schauen Sie sich zur Verdeutlichung die folgenden Codeausschnitte an:

<!-- XSLT 1.0 -->
<xsl:variable name="size">
  <xsl:choose>
    <xsl:when test="$x &gt; 3">groß</xsl:when>
    <xsl:otherwise>klein</xsl:when>
  </xsl:choose>
</xsl:variable>
    

<!-- XSLT 2.0 -->
<xsl:variable name="size" select="if ($x gt 3) then 'groß' else 'klein' "/>

Ich denke, die meisten Leser werden die als zweite gezeigte XPath 2.0-Lösung der vorstehenden XSLT 1.0-Lösung vorziehen.

Ein wichtiges Faktum bezüglich des XPath-Bedingungsausdrucks ist, dass das else nicht optional ist. C-Programmierer können dieses Konstrukt verstehen, indem sie es mit dem Ausdruck a ? b : c vergleichen. Oft wird die leere Sequenz () verwendet, wenn es keinen anderen sinnvollen Wert für den else-Teil des Ausdrucks gibt.

Bedingungsausdrücke sind nützlich, um Vorgabewerte festzulegen, wenn man kein Schema hat, das Vorgaben liefert.

(: Angeben einer Vorgabe für den Wert eines optionalen Attributs :)

if (@optional) then @optional else 'irgendeine-Vorgabe'

(: Angeben einer Vorgabe für den Wert eines optionalen Elements :)

if (optional) then optional else 'irgendeine-Vorgabe'

Eine weitere gute Anwendung ist der Umgang mit undefinierten oder unerwünschten Ergebnissen in Ausdrücken. In diesem Beispiel haben wir einen anwendungsspezifischen Grund, 0 anstelle von number('Infinity') als Ergebnis vorzuziehen.

if ($divisor ne 0) then $dividend div $divisor else 0

Sie können auch Bedingungen erzeugen, die komplexer sind. Folgender Code erzeugt eine Aufzählungsliste:

if (size eq 'XXL') then 50
else if (size eq 'XL') then 45
else if (size eq 'L') then 40
else if (size eq 'M') then 34
else if (size eq 'S') then 32
else if (size eq 'XS') then 29
else -1

In diesem Fall allerdings ist eine Lösung, die Sequenzen einsetzt, wahrscheinlich sauberer, vor allem, wenn Sie die literalen Sequenzen durch Variablen ersetzen, die über eine externe XML-Datei initialisiert werden könnten.

(50,45,40,34,32,29,-1)[(index-of((('XXL', 'XL', 'L', 'M', 'S', 'XS')), size), 7)[1]]

Wir nehmen hier an, dass der Kontext nur ein einziges size-Kindelement besitzt, ansonsten ist der Ausdruck nicht zulässig (Sie könnten dann aber stattdessen size[1] schreiben). Wir verlassen uns außerdem auf die Tatsache, dass index-of eine leere Sequenz zurückliefert, wenn das gesuchte Objekt (das wir mit 7 verketten, um den else-Fall zu behandeln) nicht gefunden wird.

  

<< zurück vor >>

 

 

 

Tipp der data2type-Redaktion:
Zum Thema XSLT bieten wir auch folgende Schulungen zur Vertiefung und professionellen Fortbildung an:

Copyright © 2006 O'Reilly Verlag GmbH & Co. KG
Für Ihren privaten Gebrauch dürfen Sie die Online-Version ausdrucken.
Ansonsten unterliegt dieses Kapitel aus dem Buch "XSLT Kochbuch" denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

O'Reilly Verlag GmbH & Co. KG, Balthasarstraße 81, 50670 Köln, kommentar(at)oreilly.de