Zählen, Summieren und Runden
(Auszug aus "XSLT 2.0 & XPath 2.0" von Frank Bongers, Kapitel 2.)
Mit XPath-Funktionen ist es auch möglich, Knoten zu zählen und numerische Inhalte zu summieren. Hierzu dienen die Funktionen fn:count() respektive fn:sum(). Eine so gebildete Summe kann XPath auch runden, wobei neben den landläufigen, weitestgehend selbsterklärenden Funktionen fn:round(), fn:floor() und fn:ceiling() auch die originellere Funktion fn:round-half-to-even() zur Verfügung steht. Anhand der Buchliste lassen sich alle demonstrieren.
Zählen mit XPath – fn:count()
Im Dokument befinden sich Bücher mit und ohne Angabe der ISBN. Interessant zu wissen wäre, wie viele von jeder Gruppe enthalten sind. Hier hilft die Funktion fn:count(), die sich ihre eigene Sequenz zusammenstellt und die Items zählt. Zunächst werden pauschal alle Bücher gezählt, was am sinnvollsten in der Template-Regel für <buchhandel> geschieht:
<xsl:template match="buchhandel">
<p><b>Statistik:</b></p>
<p>Bücher in der Liste: <xsl:value-of select="fn:count(buch)"/></p>
<xsl:apply-templates select="buch"/>
</xsl:template>
Ausgehend von <buchhandel> als Current Node bildet fn:count(buch) eine Sequenz aller Buch-Elemente und gibt deren Anzahl zurück. Das lässt sich durch Predicates noch präzisieren:
<xsl:template match="buchhandel">
<p><b>Statistik:</b></p>
<p>Bücher in der Liste: <xsl:value-of select="fn:count(buch)"/>; davon mit ISBN: <xsl:value-of select="fn:count(buch[@isbn!=''])"/>; ohne ISBN: <xsl:value-of select="fn:count(buch[fn:not(@isbn!='')])"/>;</p>
<xsl:apply-templates select="buch"/>
</xsl:template>
Code-Beispiel: kap02/2.03.3/buchhandel-count-sum.xsl (Auszug).
Die Ausgabe sieht so aus:
Bücher in der Liste: 27; davon mit ISBN: 12; ohne ISBN: 15;
Summieren mit XPath – fn:sum()
Wollen Sie in Zusammenhang mit dieser Liste den Gesamtpreis aller Bücher erfahren – es sei dahingestellt, wie sinnvoll das ist –, so ist dies mit Hilfe der Funktion fn:sum() darzustellen. Die oben begonnene Statistik wird erweitert:
...
<p>Gesamtpreis aller Bücher: <xsl:value-of select="fn:sum(buch/preis)"/></p>
...
Code-Beispiel: kap02/2.03.3/buchhandel-count-sum.xsl (Auszug).
Der ausgegebene Preis beträgt 612.7, was für Preisangaben nicht den Gepflogenheiten entspricht. Das ist zu beheben. Vorher wäre noch der Durchschnittspreis zu errechnen. Die Zahl der Bücher wurde eben schon mit fn:count() ermittelt, hier geht dies ebenfalls vonstatten:
<p>Durchschnittspreis aller Bücher: <xsl:value-of select="fn:sum(buch/preis) div fn:count(buch)"/></p>
Code-Beispiel: kap02/2.03.3/buchhandel-count-sum.xsl (Auszug).
Zu beachten ist der Operator div. Das in anderen Sprachen für Division verwendete Symbol / ist in XPath anderweitig belegt und kann deshalb nicht in dieser Bedeutung eingesetzt werden. Die anderen Rechenoperatoren sind die gewohnten, also +, – , *. Dazu kommen noch mod für Modulo und idiv für Ganzzahldivision. Man käme in Versuchung, Letzteres hier alternativ anzuwenden (Anmerkung: Mit idiv erhalten Sie einen Fehler, weil dann der erste Operand strikt eine Ganzzahl (Integer) sein muss, was aber hier nicht der Fall ist.); als Ergebnis erhält man nämlich 22.6925925925925925926.
Glücklicherweise bietet XPath auch die Möglichkeit zu runden.
Runden mit XPath – fn:round(), fn:floor(), fn:ceiling(), fn:round-half-to-even()
Zunächst können Sie versuchen, der Situation mit fn:round() Herr zu werden. Dies ist nicht weiter schwer. Der Ausdruck wird allerdings langsam »schachtelig«:
<p>Durchschnittspreis aller Bücher: <xsl:value-of select="fn:round(fn:sum(buch/preis) div fn:count(buch))"/></p>
Code-Beispiel: kap02/2.03.3/buchhandel-count-sum-round.xsl (Auszug).
Dies rundet nach 23 auf und verhält sich damit identisch zur Funktion fn:ceiling(), während die Funktion fn:floor() nach 22 abrundet. Richtig befriedigend ist dies nicht, denn für Preisangaben wären zwei Nachkommastellen genauer.
Genau dies lässt sich mit fn:round-half-to-even() erzielen. Die Funktion nimmt ein zweites Argument entgegen, das die Rundungspräzision beschreibt. Hier eine 2 zu übergeben, bewirkt genau die angestrebte Stellenzahl:
fn:round-half-to-even(fn:sum(buch/preis) div fn:count(buch),2)
Code-Beispiel: kap02/2.03.3/buchhandel-count-sum-roundeven.xsl (Auszug).
Die Ausgabe lautet hiermit:
Durchschnittspreis aller Bücher: 22.69
Zahlen formatieren mit format-number()
Als kleine kosmetische Nachbesserung wäre noch die Erweiterung des Gesamtpreises auf zwei Nachkommastellen zu erledigen. Hier nochmals fn:round-half-to-even() ins Feld zu führen, nützt jedoch nichts; denn diese Funktion kann nur überschüssige Nachkommastellen entfernen, zum Anfügen folgender Nullen ist sie nicht in der Lage.
Dies ist mittels der XSLT-Funktion format-number() zu erreichen. Neben der Eingabezahl nimmt die Funktion einen Muster-String (Anmerkung: Die Funktion ist viel komplexer als hier dargestellt. Hierzu möchte ich auf die Referenz der XSLT- und XPath-Funktionen verweisen.) entgegen, in dem die Stellen durch Platzhalter vertreten sind. Dabei markiert # eine Stelle, die entfallen darf, die 0 dagegen eine stets auszugebende Stelle, die im Bedarfsfall eine 0 erhält.
Folgender Aufruf führt hier zum Ziel:
format-number(fn:sum(buch/preis),'##00.00')
Code-Beispiel: kap02/2.03.3/buchhandel-count-sum-format.xsl (Auszug).
Die Ausgabe lautet jetzt:
Gesamtpreis aller Bücher: 612.70
Wollen Sie sichergehen, dass die oben mit fn:round-half-to-even() auf zwei Nachkommastellen getrimmte Zahl auch zuverlässig so ausgegeben wird (es könnte sich ja auch mal ein glatterer Durchschnittspreis ergeben), dann sollten Sie format-number() auch hier zusätzlich anwenden:
format-number(fn:round-half-to-even(fn:sum(buch/preis) div fn:count(buch), 2),'##00.00')
Code-Beispiel: kap02/2.03.3/buchhandel-count-sum-format.xsl (Auszug).
Optisch ändert dies hier nichts, es handelt sich lediglich um einen kleinen Rettungsanker. Die Statistik des Buchverzeichnisses soll vorläufig abgeschlossen sein. Nun können wir die Reihenfolge der Ausgabe der Bücher angehen.
<< zurück | vor >> |
Tipp der data2type-Redaktion: Zum Thema XSLT bieten wir auch folgende Schulungen zur Vertiefung und professionellen Fortbildung an: |
Copyright © Galileo Press, Bonn 2008
Für Ihren privaten Gebrauch dürfen Sie die Online-Version ausdrucken.
Ansonsten unterliegt dieses Kapitel aus dem Buch "XSLT 2.0 & XPath 2.0 ― Das umfassende Handbuch" 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.
Galileo Press, Rheinwerkallee 4, 53227 Bonn