2010-05-04 9 views
14

Für jeden "Agentur" -Knoten muss ich die "stmt" -Elemente finden, die die gleichen key1-, key2-, key3-Werte haben und nur einen "stmt" -Knoten mit "comm" und ausgeben "Prem" -Werte summiert zusammen. Für alle "stmt" -Elemente innerhalb dieser "Agentur", die nicht mit anderen "stmt" -Elementen übereinstimmen, die auf key1, key2 und key3 basieren, muss ich sie so ausgeben, wie sie sind. Nach der Umwandlung hätte der erste "Agentur" -Knoten also nur zwei "stmt" -Knoten (einen summierten) und der zweite "Agentur" -Knoten würde unverändert weitergegeben, da die Schlüssel nicht übereinstimmen. XSLT 1.0 oder 2.0 Lösungen sind in Ordnung ... obwohl mein Stylesheet aktuell 1.0 ist. Beachten Sie, dass die Agenturknoten eine beliebige Anzahl von "stmt" -Elementen haben können, die übereinstimmende Schlüssel haben, die gruppiert und summiert werden müssen, und jede Zahl, die dies nicht tun.Wie gruppiere und summiere ich Werte in XSLT

<statement> 
<agency> 
    <stmt> 
     <key1>1234</key1> 
     <key2>ABC</key2> 
     <key3>15.000</key3> 
     <comm>75.00</comm> 
     <prem>100.00</prem> 
    </stmt> 
    <stmt> 
     <key1>1234</key1> 
     <key2>ABC</key2> 
     <key3>15.000</key3> 
     <comm>25.00</comm> 
     <prem>200.00</prem> 
    </stmt> 
    <stmt> 
     <key1>1234</key1> 
     <key2>ABC</key2> 
     <key3>17.50</key3> 
     <comm>25.00</comm> 
     <prem>100.00</prem> 
    </stmt> 
</agency> 
<agency> 
    <stmt> 
     <key1>5678</key1> 
     <key2>DEF</key2> 
     <key3>15.000</key3> 
     <comm>10.00</comm> 
     <prem>20.00</prem> 
    </stmt> 
    <stmt> 
     <key1>5678</key1> 
     <key2>DEF</key2> 
     <key3>17.000</key3> 
     <comm>15.00</comm> 
     <prem>12.00</prem> 
    </stmt> 
</agency> 

+0

Gute Frage (+1). Sehen Sie meine Antwort für eine komplette XSLT 1.0 Lösung. –

Antwort

10

Und eine XSLT-2.0-Lösung:

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:xs="http://www.w3.org/2001/XMLSchema" 
exclude-result-prefixes="xs" 
> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 

<xsl:template match="node()|@*"> 
    <xsl:copy> 
    <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="agency"> 
    <agency> 
    <xsl:for-each-group select="stmt" group-by= 
    "concat(key1, '+', key2, '+', key3)"> 

    <stmt> 
     <xsl:copy-of select= 
     "current-group()[1]/*[starts-with(name(),'key')]"/> 

     <comm> 
     <xsl:value-of select="sum(current-group()/comm)"/> 
     </comm> 
     <prem> 
     <xsl:value-of select="sum(current-group()/prem)"/> 
     </prem> 
    </stmt> 
    </xsl:for-each-group> 
    </agency> 
</xsl:template> 
</xsl:stylesheet> 
+0

Die 'concat (key1, key2, key3)' wird in bestimmten Fällen fehlschlagen, zum Beispiel 'key1 =" 1A "key2 =" B "key3 =" 1.000 "' und 'key1 =" 1 "key2 =" AB "key3 =" 1.000 "' ... Ich glaube, dass die Verkettung von Strings ohne genaue Kenntnis ihres Inhalts (oder ihrer Einschränkung) falsch ist. – Lucero

+0

@Lucero: Nochmals vielen Dank, es ist nichts falsch mit der Concat - es war etwas rutschte von mir aus - ich fühle mich heute den ganzen Tag so müde - die jetzt korrigiert ist. Bitte lassen Sie mich wissen, ob die Korrektur Sie zufriedenstellt. Diese Korrektur ist typisch für solche Lösungen. –

+0

@Dimitre, im Gegensatz zu den anderen "concat" -Problemen ist das '+' hier kein geeignetes Trennzeichen, da die XML-Daten theoretisch sehr gut Schlüsselstrings mit '+' enthalten können - denken Sie an 'key1 =" 1 + "key2 =" 2 "' und 'key1 =" 1 "key2 =" + 2 "'.Also mein Sprichwort ist, dass Sie nur dann concat, wenn Sie wissen, dass das Trennzeichen nie Teil der verketteten Daten sein wird. – Lucero

7

in XSLT 1.0 Die Muench-Methode für die Gruppierung (mit Verbindung Schlüssel) verwenden.

Diese Transformation:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 

<xsl:key name="kStmtByKeys" match="stmt" 
     use="concat(generate-id(..), key1, '+', key2, '+', key3)"/> 

<xsl:template match="node()|@*"> 
    <xsl:copy> 
    <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="agency"> 
    <agency> 
    <xsl:for-each select= 
    "stmt[generate-id() 
      = 
      generate-id(key('kStmtByKeys', 
          concat(generate-id(..), key1, '+', key2, '+', key3) 
          )[1] 
         ) 
      ] 
    "> 
     <xsl:variable name="vkeyGroup" select= 
     "key('kStmtByKeys', concat(generate-id(..), key1, '+', key2, '+', key3))"/> 

    <stmt> 
     <xsl:copy-of select="*[starts-with(name(), 'key')]"/> 
     <comm> 
     <xsl:value-of select="sum($vkeyGroup/comm)"/> 
     </comm> 
     <prem> 
     <xsl:value-of select="sum($vkeyGroup/prem)"/> 
     </prem> 
    </stmt> 
    </xsl:for-each> 
    </agency> 
</xsl:template> 
</xsl:stylesheet> 

wenn auf der mitgelieferten XML-Dokument angewendet wird, erzeugt das gewünschte Ergebnis:

<statement> 
    <agency> 
     <stmt> 
      <key1>1234</key1> 
      <key2>ABC</key2> 
      <key3>15.000</key3> 
      <comm>100</comm> 
      <prem>300</prem> 
     </stmt> 
     <stmt> 
      <key1>1234</key1> 
      <key2>ABC</key2> 
      <key3>17.50</key3> 
      <comm>25</comm> 
      <prem>100</prem> 
     </stmt> 
    </agency> 
    <agency> 
     <stmt> 
      <key1>5678</key1> 
      <key2>DEF</key2> 
      <key3>15.000</key3> 
      <comm>10</comm> 
      <prem>20</prem> 
     </stmt> 
     <stmt> 
      <key1>5678</key1> 
      <key2>DEF</key2> 
      <key3>17.000</key3> 
      <comm>15</comm> 
      <prem>12</prem> 
     </stmt> 
    </agency> 
</statement> 
+0

Wenn ich die Frage richtig verstanden habe, ist Ihre Lösung kaputt, wenn eine andere Agentur Knoten mit den gleichen Schlüsseln hat. Mir scheint, dass die muenchische Methode mit dem globalen Schlüssel nicht funktioniert, da es mehrere Agenturen gibt. – Lucero

+0

@Lucero: Eine gute Beobachtung, danke. Dies ist jetzt korrigiert und ich benutze immer noch die Muenchian-Methode mit einem Compond-Schlüssel. –

+0

Hm, ist diese Art der Generierung eines zusammengesetzten Schlüssels garantiert, um die gewünschten Ergebnisse in allen Situationen zu geben? Wenn ein Schlüssel 'concat (' 1 ',' 23 ') 'und ein anderer' concat ('12 ',' 3 ')' ist (Sie erhalten die Idee), kann dies Probleme verursachen, abhängig vom Eingabedokument und vom XSLT-Prozessor . – Lucero

1
<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"> 
    <xsl:output method="xml" indent="yes"/> 

    <xsl:template match="/|*"> 
     <xsl:copy> 
      <xsl:apply-templates select="*" /> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="stmt"> 
     <xsl:variable name="stmtGroup" select="../stmt[(key1=current()/key1) and (key2=current()/key2) and (key3=current()/key3)]" /> 
     <xsl:if test="generate-id()=generate-id($stmtGroup[1])"> 
      <xsl:copy> 
       <key1> 
        <xsl:value-of select="key1"/> 
       </key1> 
       <key2> 
        <xsl:value-of select="key2"/> 
       </key2> 
       <key3> 
        <xsl:value-of select="key3"/> 
       </key3> 
       <comm> 
        <xsl:value-of select="format-number(sum($stmtGroup/comm), '#.00')"/> 
       </comm> 
       <prem> 
        <xsl:value-of select="format-number(sum($stmtGroup/prem), '#.00')"/> 
       </prem> 
      </xsl:copy> 
     </xsl:if> 
    </xsl:template> 
</xsl:stylesheet> 
Verwandte Themen