XML | XML-Schema | XPath | XSL-T | XSL-FO | XQuery | XProc | SVG |
XSL-T / Die XSLT - Struktur / xsl:for-each-group
![]() |
![]() |
➪ xsl:for-each-group ist in der Lage, eine durch XPath ausgewählte Itemlist durch einen gewählten Grupperungsschlüssel so zusammenzufassen, dass die in der Itemlist wiederholt aufgeführten Werte jeweils nur einmal auftauchen (etwa analog einer DISTINCT-Auswertung bei einer SQL-Datenbankabfrage). Anschließend kann die gruppierte Itemliste durch xsl:for-each select='current-group()' durchlaufen werden.
Auf dieser Seite:Siehe
<xsl:for-each-group
select = expression
group-by? = expression
group-adjacent? = expression
group-starting-with? = pattern
group-ending-with? = pattern
collation? = { uri }>
<!-- Content: (xsl:sort*, sequence-constructor) -->
</xsl:for-each-group>
Siehe auch https://www.w3.org/TR/xslt20/#element-for-each-group.
Siehe auch https://www.w3.org/TR/xslt-30/#element-for-each-group.
Grundsätzlich geht es bei xsl:for-each-group darum, eine Sequenz von Items über einen gewählten Schlüssel (der im weiteren Programmverlauf durch current-grouping-key() ansprechbar ist) zu gruppieren (vgl. XQuery). Das Ergebnis ist wiederum eine Sequenz von Items, die durch eine Schleife über die current-group() weiter ausgewertet werden kann.
<xsl:for-each-group
select="/Orte/Ort/Mensch/Kauf"
group-by="bez"/>
Möchten Sie die Eingangssequenz weiter eingrenzen, können Sie mit den bewährten Prädikaten arbeiten.
<xsl:for-each-group
select="/Orte/Ort/Mensch/Kauf
[(anzahl * preis) > 1000]"
group-by="bez"/>
Die vorstehende Eingangssequenz können Sie alternativ auch so formulieren:
<xsl:for-each-group
select="for $x in /Orte/Ort/Mensch/Kauf
return
if ($x[(anzahl * preis) > 1000])
then $x
else ()"
group-by="bez"/>
Syntaktisch keine Verbesserung, aber didaktisch von Wert ist die Option über except.
<xsl:for-each-group
select="/Orte/Ort/Mensch/Kauf
except
/Orte/Ort/Mensch/Kauf
[(anzahl * preis) <= 1000]"
group-by="bez">
Unter XSLT 3.0 besteht auch die Möglichkeit, mit for-each und einer selbst definierten Funktion zu arbeiten.
<xsl:for-each-group
select="for-each(/Orte/Ort/Mensch/Kauf,
function($p){
$p[(anzahl * preis) > 1000]
})"
group-by="bez"/>
Ebenfalls unter XSLT 3.0 können Sie mit der filter-Funktion unser Ziel erreichen.
<xsl:for-each-group
select="filter (/Orte/Ort/Mensch/Kauf,
function($p) {
($p/anzahl * $p/preis) > 1000
})"
group-by="bez">
Leistungsfähig und hilfreich sind die Gruppierungen über xsl:for-each-group, nicht zuletzt kombiniert mit mehreren Ausgabedokumenten, die via xsl:result-document generiert werden.
<xsl:template name="gruppierungen">
<Waren>
<xsl:for-each-group
select="/Orte/Ort/Mensch/Kauf"
group-by="bez">
<xsl:result-document
href="../output/{current-grouping-key()}.xml">
<ERGEBNIS>
<ware key="{ current-grouping-key() }">
<xsl:for-each select="current-group()">
<Kauf>
<Artikel>
<xsl:value-of select="bez"/>
</Artikel>
<Anzahl>
<xsl:value-of select="anzahl"/>
</Anzahl>
<Umsatz>
<xsl:value-of select="Gesamt"/>
</Umsatz>
<VNKunde>
<xsl:value-of select="../vorname"/>
</VNKunde>
<NNKunde>
<xsl:value-of select="../name"/>
</NNKunde>
<WOKunde>
<xsl:value-of select="../../name"/>
</WOKunde>
</Kauf>
</xsl:for-each>
</ware>
</ERGEBNIS>
</xsl:result-document>
</xsl:for-each-group>
</Waren>
</xsl:template>
Die Anweisung xsl:for-each-group ermöglicht es, eine klar definierte Datenmenge (im folgenden Beispiel "//Ort[3]/Mensch/Kauf") nach einem Schlüssel (hier: bez, ist ein Childnode von Kauf) zu gruppieren. Eventuell mehrfach auftretende Werte dieses Schlüssels (der current-grouping-key()) werden jeweils nur ein einziges Mal wiedergegeben; damit ist die Gruppierung der distinct-values-Funktion eng verwandt.
Hinter jeder einzelnen Gruppierung (der current-group()) stehen aber noch gegebenenfalls mehrere Einzelwerte, die Sie mit einer Schleife ansprechen können. Im dargestellten Beispiel habe ich nach dem Kauf-Element bez gruppiert, daher treten die im XML-Input ursprünglich mehrfach auftretenden Einzelwerte "Hemd", "Hose", "Schuhe" im HTML-Output nur ein einziges Mal auf. Um den Bezug vom XML-Input zum HTML-Output übersichtlich zu halten, habe ich drei Einzelfelder farblich markiert und mit Pfeilen verbunden. Die XSL-Logik sieht so aus:
<xsl:template match="/">
<html>
<body>
<table border="1">
<xsl:for-each-group
select="//Ort[3]/Mensch/Kauf"
group-by="bez">
<tr>
<td valign="top">
<xsl:value-of
select="current-grouping-key()" />
</td>
<td>
<table>
<xsl:for-each
select="current-group()">
<xsl:sort
select="anzahl"
data-type="number"
order="ascending" />
<tr>
<td><xsl:value-of select="idMensch"/></td>
<td><xsl:value-of select="anzahl"/></td>
<td><xsl:value-of select="preis"/></td>
<td><xsl:value-of select="Gesamt"/></td>
</tr>
</xsl:for-each>
</table>
</td>
</tr>
</xsl:for-each-group>
</table>
</body>
</html>
</xsl:template>
Siehe auch Gruppieren in XPath 1.0/XSL 1.0 und LINQ.
wg / 10. August 2020
Fragen? Anmerkungen? Tipps?
Bitte nehmen Sie Kontakt zu mir auf.
ᐅ xsl:fork
V.i.S.d.P.: Wilfried Grupe * Klus 6 * 37643 Negenborn
☎ 0151. 750 360 61 * eMail: info10@wilfried-grupe.de