Thomas J.S.: XSLT - Sortieren und doppelte Einträge unterdrücken

Beitrag lesen

Hallo,

<xsl:variable name="position"><xsl:value-of select="position() mod 2"></xsl:value-of> </xsl:variable>

variable select="position() mod 2" name="position"

Hier verstehe ich aber auch  nicht genau, worauf Du hinaus willst.(?)

Dass du es abkürzen kannst ;-)

Wie kann das sein? - bezieht sich position() nach sort nicht doch auf das sortierte Knotenset???

Nein, das ist schon OK so. Denn mit for-each selektierst du eine Knotenmenge, alle weitere Angaben in diesem Template (ja, auch for-ech ist ein Template, aber das soll uns jetzt nicht kümmern) gelten für diese Knotenmenge. So wird es immer noch nach position() im Dokument gearbeitet, aber mit der Einschrenkung, dass dabei nur diese Knotenmenge beachtet wird. Deshalb funktioniert es auch, wenn du Knoten vertauschst.

Das will mir immer noch nicht ganz eingehen.
Nochmal ein Beispiel:

<bsp>B</bsp> (pos 1)
<bsp>A</bsp> (pos 2)
<bsp>C</bsp> (pos 3)
...
<xsl:sort />
...
Knoten sortiert aber aber position() wie im Dokument stelle ich mir dann so vor:
<bsp>A</bsp> (pos 2)
<bsp>B</bsp> (pos 1)
<bsp>C</bsp> (pos 3)
Was ist jetzt <xsl:value-of select="bsp[position() = 2] />?
A, oder? -

Das kommt darauf an ;-)
Vielleicht nochmal die Erklärung:
xsl:sort bestimmt die Reihenfolge in welcher die selektierten Knoten abgearbeitet werden. Wenn kein Sortierkriterium angegeben ist (im select="") dann werden die Konten in Dokumentordnung abgearbeitet (nicht vergessen: die Voreinstellung für sort ist "selext='.'" als String).

Jetzt ein Beispiel:

<?xml version="1.0"?>
<data>
 <bsp>B (pos 1)</bsp>
 <bsp>A (pos 2)</bsp>
 <bsp>C (pos 3)</bsp>
 <subdata>
  <bsp>D (pos 4)</bsp>
  <bsp>F (pos 5)</bsp>
  <bsp>E (pos 6)</bsp>
 </subdata>
</data>
--------------------------
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
 <html>
  <head>
   <title>Untitled</title>
  </head>
  <body>
   <xsl:apply-templates />
  </body>
 </html>
</xsl:template>

<xsl:template match="data">
 <h3>Alle Elemente</h3>
 <div>
  <h4>ohne "sort"</h4>
  <xsl:for-each select="//bsp">
   <span>
   <xsl:if test="position() mod 2 = 0"><xsl:attribute name="style">background:silver;</xsl:attribute></xsl:if>
   [Position: <xsl:value-of select="position()" />] Inhalt: <xsl:value-of select="." />
   </span><br />
  </xsl:for-each>
 </div>
 <div>
  <h4>mit "sort"</h4>
  <xsl:for-each select="//bsp">
   <xsl:sort />
   <span>
   <xsl:if test="position() mod 2 = 0"><xsl:attribute name="style">background:silver;</xsl:attribute></xsl:if>
   [Position: <xsl:value-of select="position()" />] Inhalt: <xsl:value-of select="." />
   </span><br />
  </xsl:for-each>
 </div>
 <xsl:apply-templates select="subdata" />
</xsl:template>
<xsl:template match="subdata">
 <h3>Untermge</h3>
 <div>
  <h4>ohne "sort"</h4>
  <xsl:for-each select="bsp">
   <span>
   <xsl:if test="position() mod 2 = 0"><xsl:attribute name="style">background:silver;</xsl:attribute></xsl:if>
   [Position: <xsl:value-of select="position()" />] Inhalt: <xsl:value-of select="." />
   </span><br />
  </xsl:for-each>
 </div>
 <div>
  <h4>mit "sort"</h4>
  <xsl:for-each select="bsp">
   <xsl:sort />
   <span>
   <xsl:if test="position() mod 2 = 0"><xsl:attribute name="style">background:silver;</xsl:attribute></xsl:if>
   [Position: <xsl:value-of select="position()" />] Inhalt: <xsl:value-of select="." />
   </span><br />
  </xsl:for-each>
 </div>
</xsl:template>
</xsl:stylesheet>
----------------------

Wie du sehen kannst, wird die Angabe der Position sich verändern, weil die Knoten in der Reihenfolge des Sortierkriteriums abgearbeitet werden.
Aber dies gilt eben nur für die Ausgabe, d.h. wenn du mit "position() = 2" immer auf "A" zugreifen möchtest, funktioniert das nicht, weil die Knoten in anderen Reihenfolge abgearbeitet werden und sich dementsprechnd ihre Position  für die Ausgabe ändert.
Du kannst auch sehen, dass bei for-each immer eine bestimmte Knotenmenge selektiert wird und sich dann auch die Sortierung nur auf diese Knotenmenge bezieht.

Warum oder wie funktioniert das dann, dass trotzdem im Ergebnisbaum, würde man jeweils position() mod2 ausgeben, das Ergebnis so ist?:
1
0
1
und eben nicht
0
1
1

Das ist eine ganz andere Sache: das modulo-Operator lifert das Ergebnis einer Division, genauer den ganzzahlingen Rest einer abgeschnittenen/abgerundeten (truncating) Divison. D.h.:
1 mod 2 = 1 (1 druch 2 ist 0, bleibt 1 ...)
1:2 = 0,5
 1|0:2 = 5

2 mod 2 = 0 (2 durch 2 ist 1, bleibt 0)

3 mod 2 = 1 (3 durch 2 ist 1, bleibt 1 ...)
3:2 = 1,5
 1|0:2 = 5

4 mod 2 = 0 (4 durch 2 ist 2, bleibt 0)

5 mod 2 = 1 (5 durch 2 ist 2, bleibt 1 ...)
5:2 = 1,5
 1|0:2 = 5

5 mod -2 = 1
-5 mod 2 = -1
-5 mod -2 = -1
17 mod 5 = 2

usw.

Deshalb kann man sehr gut mit  "position() mod 2" gearde ungerade Positionen von Knoten unterscheiden. ;-)

Ich hoffe das hilft.

Grüße
Thomas