Oliver Schmidt: XSL-Transformation-Problem (XRTreeFrag cannot be cast to)

Hallo und einen schönen guten Abend,

ich hänge hier gerade an einer Anforderung und komme absolut nicht weiter. Ich versuche mit XSL 1.0 (FOP-Prozessor) eine Liste von Positionen zu errechnen, leider bekomme ich oben genannte Fehlermeldung:

javax.xml.transform.TransformerException: org.apache.xpath.objects.XRTreeFrag cannot be cast to org.apache.xpath.objects.XNodeSet

Ich habe folgendes XML (Auszug):

<root>
	<Ebene1>
		<Ebene2>
			<Position netPrice="1000" percent="2"/>
			<Position netPrice="2000" percent="4"/>
			<Position netPrice="3000" percent="2"/>
			<Position netPrice="6000" percent="1"/>
			<Position netPrice="2000" percent="2"/>
		</Ebene2>
	</Ebene1>
</root>

Die Rechnung sieht ein wenig komplizierter aus, aber ich habe die Transformation ein wenig vereinfacht. Der Fehler besteht weiterhin. Hier der XSL-Auszug, der den Fehler verursacht:

<xsl:variable name="liste">
	<xsl:for-each select="root/Ebene1/Ebene2" >
		<xsl:variable name="temp" select="((@netPrice * @percent) div 100)" />
			<xs:element type="xs:integer"><xsl:value-of select="$temp" /></xs:element>
	</xsl:for-each>
</xsl:variable>

<xsl:variable name="all" >
		<xsl:value-of select="sum($liste/*)" />
</xsl:variable>

Normalerweise würde ich erwarten, dass das Ergebnis 260 ist, da er jede Zeile einzeln addiert und zum Schluss die Summe bildet.

1000 x 2 / 100 = 20

2000 x 4 / 100 = 80

3000 x 2 / 100 = 60

6000 x 1 / 100 = 60

2000 x 2 / 100 = 40

Summe = 260

Ich könnte das Ergebnis auch so berechnen:

0,1x(A1xB1+A2xB2+A3xB3+A4xB4+A5xB5)

Aber leider ändert sich das XML jedes mal, sodass ich die Anzahl der Reihen noch nicht kenne.

Ich wäre über jeden Lösungsansatz dankbar.

Lieben Gruß und vielen Dank

Oli

  1. Hallo Oli,

    Normalerweise würde ich erwarten, dass das Ergebnis 260 ist, da er jede Zeile einzeln addiert und zum Schluss die Summe bildet.

    Mit XSLT 2.0 wäre die Lösung ein Einzeiler:

    <xsl:value-of select="sum(for $p in root/Ebene1/Ebene2/Position return $p/@netPrice * $p/@percent div 100)"/>  <!-- 260 -->
    

    Für XSLT 1.0 kommt xsl:call-template ins Spiel:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
      <xsl:template match="root/Ebene1/Ebene2">
        <xsl:call-template name="summe">
          <xsl:with-param name="p" select="Position"/>
          <xsl:with-param name="i" select="1"/>
          <xsl:with-param name="i_max" select="count(Position)"/>
          <xsl:with-param name="gesamt" select="0"/>
        </xsl:call-template>
      </xsl:template>
    
      <xsl:template name="summe">
        <xsl:param name="p"/>
        <xsl:param name="i"/>
        <xsl:param name="i_max"/>
        <xsl:param name="gesamt"/>
    
        <xsl:variable name="akt" select="$p[$i]/@netPrice * $p[$i]/@percent div 100"/>
    
        <xsl:choose>
          <xsl:when test="$i &lt; $i_max">
            <xsl:call-template name="summe">
              <xsl:with-param name="p" select="$p"/>
              <xsl:with-param name="i" select="$i + 1"/>
              <xsl:with-param name="i_max" select="$i_max"/>
              <xsl:with-param name="gesamt" select="$gesamt + $akt"/>
            </xsl:call-template>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="$gesamt + $akt"/> <!-- 260 -->
          </xsl:otherwise>
        </xsl:choose>
      </xsl:template>
    
    </xsl:stylesheet>
    

    Grüße, Thomas