XPROC * XSL-FO * SVG * XML * XML-SCHEMA * XPATH * XSL * XSLT 1.0 * XSLT 2.0 * XSLT 3.0 * XQUERY * ANT



XSL / xsl:for-each-group

xsl:for-each-group

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 in 2.0 und 3.0


<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. ). 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) &gt; 1000]" 
     group-by="bez"/>

Die vorstehende Eingangssequenz können Sie auch so formulieren:


<xsl:for-each-group 
     select="for $x in /Orte/Ort/Mensch/Kauf 
             return 
             if ($x[(anzahl * preis) &gt; 1000]) 
             then $x 
             else ()" 
     group-by="bez"/>

Syntaktisch keine Verbesserung, aber didaktisch von Wert ist die Option über .


<xsl:for-each-group 
     select="/Orte/Ort/Mensch/Kauf 
             except 
             /Orte/Ort/Mensch/Kauf
                  [(anzahl * preis) &lt;= 1000]" 
     group-by="bez">

Unter XSLT 3.0 besteht auch die Möglichkeit, mit und einer selbst definierten Funktion zu arbeiten.


<xsl:for-each-group 
     select="for-each(/Orte/Ort/Mensch/Kauf, 
             function($p){ 
               $p[(anzahl * preis) &gt; 1000] 
             })" 
     group-by="bez"/>

Ebenfalls unter XSLT 3.0 können Sie mit der -Funktion unser Ziel erreichen.


<xsl:for-each-group 
     select="filter (/Orte/Ort/Mensch/Kauf, 
              function($p) { 
                ($p/anzahl * $p/preis) &gt; 1000
              })" 
     group-by="bez">

Leistungsfähig und hilfreich sind die ü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 -Funktion eng verwandt.

pic/foreachgroup.png

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 und LINQ.

wg / 28. Juni 2020



Fragen? Anmerkungen? Tipps?

Bitte nehmen Sie Kontakt zu mir auf.






Vielen Dank für Ihr Interesse an meiner Arbeit.



V.i.S.d.P.: Wilfried Grupe * Klus 6 * 37643 Negenborn

☎ 0151. 750 360 61 * eMail: info10@wilfried-grupe.de

www.wilfried-grupe.de/XSL_for_each_group.html