Gern stehe ich zur fachlichen Unterstützung in XML-Technologien, C#.NET, VisualBasic.NET und Java zur Verfügung. Sprechen Sie mich einfach an: Mail oder ☎ 0151 . 750 360 61


XSL-Übersicht / xsl:for-each select

xsl:for-each select

xsl:for-each select

xsl:for-each select erlaubt eine effiziente Programmierung auf Basis komplexer, klar definierter Datenstrukturen, die sich beispielsweise aus verschachtelten Datenbankabfragen ergeben. Ein hilfreicher Trick ist auch der Loop allein um das Root-Element.

Auf dieser Seite:

Definition

In XSLT 1.0 können Sie xsl:for-each select so verwenden:


<xsl:for-each
  select = node-set-expression>
  <!-- Content: (xsl:sort*, template) -->
</xsl:for-each>

Siehe auch https://www.w3.org/TR/xslt-10/#element-for-each.

In XSLT 2.0 und 3.0 bieten sich erweiterte Möglichkeiten f+r xsl:for-each select:


<xsl:for-each
  select = expression>
  <!-- Content: (xsl:sort*, sequence-constructor) -->
</xsl:for-each>

Siehe auch https://www.w3.org/TR/xslt20/#element-for-each.

Siehe auch https://www.w3.org/TR/xslt-30/#element-for-each.

Praktische Anwendung

Das erste Beispiel listet lediglich alle Ortsnamen aus dem XML-Quelldokument auf. Das xsl:template match='/' definiert das Ausgabedokument mit HTML-spezifischen Tags; an passender Stelle wird über eine XSL-Schleife eine Liste aller Ort -Knoten angesprochen, die über XPath definiert werden kann. Mit xsl:value-of select wird dann der Inhalt eines Elements ausgelesen, der wiederum über XPath definiert werden kann, hier: der Childnode name von jedem Ort.


<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
    <html>
      <body>
        <h3>Transformation aus XML</h3>
        <xsl:for-each select="/Orte/Ort">
          <p>
            Der Ort heisst 
           <b>
              <xsl:value-of select="name"/>
           </b>
          </p>
        </xsl:for-each>
      </body>
    </html>
  </xsl:template>
</xsl:stylesheet>

Counter in xsl:for-each select

Das folgende XSLT-2.0-Beispiel listet alle Werte von 1 bis 20 auf, die ohne Rest durch 3 teilbar sind, und nummeriert die Ergebnisse.


<ergebnis>
  <xsl:for-each select="(1 to 20)[. mod 3 = 0]">
    <wert>
        <xsl:attribute name="Nr">
            <xsl:value-of select="position()"/>
        </xsl:attribute>
        <xsl:value-of select="."/>
    </wert>
  </xsl:for-each>
</ergebnis>

So sieht das Ergebnis aus:


<ergebnis>
   <wert Nr="1">3</wert>
   <wert Nr="2">6</wert>
   <wert Nr="3">9</wert>
   <wert Nr="4">12</wert>
   <wert Nr="5">15</wert>
   <wert Nr="6">18</wert>
</ergebnis>

Sie möchten die gesamte Anzahl der Loops ebenfalls in der Nummerierung finden? Arbeiten Sie mit :


<ergebnis>
  <xsl:for-each select="(1 to 20)[. mod 3 = 0]">
    <wert>
        <xsl:attribute name="Nr">
            <xsl:value-of select="concat(position(), ' von ', last())" />
        </xsl:attribute>
        <xsl:value-of select="."/>
    </wert>
  </xsl:for-each>
</ergebnis>

Ist das eher in Ihrem Sinn?


<ergebnis>
   <wert Nr="1 von 6">3</wert>
   <wert Nr="2 von 6">6</wert>
   <wert Nr="3 von 6">9</wert>
   <wert Nr="4 von 6">12</wert>
   <wert Nr="5 von 6">15</wert>
   <wert Nr="6 von 6">18</wert>
</ergebnis>

Verschachtelte Schleifen mit xsl:for-each select

Es kommt häufiger vor, dass eine xsl:for-each select-Schleife eine innere xsl:for-each select-Schleife beinhaltet.


<ergebnis>
  <xsl:for-each select="3 to 5">
    <xsl:variable name="v" select="."/>
    <Divisor wert="{$v}">
        <xsl:for-each select="(1 to 20)[. mod $v = 0]">
            <xsl:sort select="." 
                      data-type="number" 
                      order="descending"/>
            <wert Nr="{concat(position(), ' von ', last())}">
                <xsl:value-of select="."/>
            </wert>
        </xsl:for-each>        
    </Divisor>
  </xsl:for-each>
</ergebnis>

Das Ergebnis stellt dar, was diese Schleifenkonstruktion gezaubert hat:


ergebnis>
   <Divisor wert="3">
      <wert Nr="1 von 6">18</wert>
      <wert Nr="2 von 6">15</wert>
      <wert Nr="3 von 6">12</wert>
      <wert Nr="4 von 6">9</wert>
      <wert Nr="5 von 6">6</wert>
      <wert Nr="6 von 6">3</wert>
   </Divisor>
   <Divisor wert="4">
      <wert Nr="1 von 5">20</wert>
      <wert Nr="2 von 5">16</wert>
      <wert Nr="3 von 5">12</wert>
      <wert Nr="4 von 5">8</wert>
      <wert Nr="5 von 5">4</wert>
   </Divisor>
   <Divisor wert="5">
      <wert Nr="1 von 4">20</wert>
      <wert Nr="2 von 4">15</wert>
      <wert Nr="3 von 4">10</wert>
      <wert Nr="4 von 4">5</wert>
   </Divisor>
</ergebnis>

Präzise XPath-Adressierung

Mit der Anweisung xsl:for-each ist es möglich, dem select-Attribut ein XPath-Statement zu übergeben, das aus einem XML-Input gezielt Werte auswählt. In der folgenden Abbildung werden lediglich Mensch-Elemente ausgewählt, deren Gehalt unter 1000 liegt. Die beiden Einträge Nicole Nixlos und Stefan Sprachlos, deren Gehalt-Elemente darüber liegen, werden ignoriert.

pic/foreach.png

Eine zusätzliche -Anweisung sorgt dafür, dass die Ergebnisliste inhaltlich sortiert wird, und zwar absteigend nach dem Gehalt. Dadurch wird die ursprüngliche Reihenfolge verworfen und in eine neue Reihenfolge transformiert, sodass über die position()-Funktion eine Nummerierung eingefügt wird. Siggi Sorglos, der in der ursprünglichen Reihenfolge an 5. Stelle lag, kommt nun in der Zielstruktur auf Platz 1. Hugo Holzflos lag in der ursprünglichen Reihenfolge auf Platz 1, liegt nun auf Platz 4.

Die dazugehörige Implementierung sieht folgendermaßen aus:


 <xsl:template match="/">
  <html>
   <body>
    <table>
     <xsl:for-each 
          select="//Mensch[Gehalt &lt; 1000]">
      <xsl:sort 
           select="Gehalt" 
           data-type="number" 
           order="descending" />
      <tr>
       <td>
        <xsl:value-of select="position()" />
       </td>
       <td>
        <xsl:value-of select="id" />
       </td>
       <td>
        <xsl:value-of select="name" />
       </td>
       <td>
        <xsl:value-of select="vorname" />
       </td>
       <td>
        <xsl:value-of select="Gehalt" />
       </td>
       <td>
        <xsl:value-of select="idOrt" />
       </td>
      </tr>
     </xsl:for-each>
    </table>
   </body>
  </html>
 </xsl:template>

Der initiale Loop

Ein hilfreicher Trick, um das XML-Quelldokument effizient auswerten zu können, ist der Loop allein um das Root-Element.

Diese Schleife ergibt zwar nur ein einziges Element. Oder gar keins, falls das Input-Dokument bereits im Root-Element nicht zur XSL-Programmierung passt. Letzteres ist eine hilfreiche Kontrolle, falls der Datenlieferant die Dokumentstruktur geändert hat, ohne dass die Änderung im XSL-Code nachvollzogen ist. In diesem Fall ist der gesamte Output nämlich leer.


<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" 
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
    <xsl:for-each select="/Orte">
      <html>
        <body>
          <h3>Transformation aus XML</h3>
          <xsl:for-each 
               select="Ort[id != '2']/Mensch">
              <!-- weitere Logik -->
          </xsl:for-each>
        </body>
      </html>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

Der Vorteil: Sie können mit dem Root-Element, das sich aus dem initialen Loop ergibt, im weiteren eine übersichtliche Programmierlogik beibehalten, die sich nicht in externe Template-Aufrufe verliert und sich daher leicht pflegen lässt. Innerhalb des äußeren Loops können weitere Schleifen, Bedingungen etc. implementiert werden.

Mehr zum Thema: , .

wg / 8. Januar 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_select.html