XSLT 中基于分组的计算问题

Problem with computation based on Grouping in XSLT

这里有一种情况,我需要从一个存在的节点中获取一个值并将其用于计算值。

这是我的 XML:

<?xml version="1.0" encoding="utf-8"?>
<Document>
  <Header>
    <FirstName>Joel</FirstName>
    <LastName>Cabarles</LastName>
    <InvoiceDate>01-JAN-2020</InvoiceDate>
    <InvoiceNumber>123</InvoiceNumber>
    <Currency>PHP</Currency>
    <ExchangeRate>1.5</ExchangeRate>
  </Header>
  <InvoiceLines>
    <Lines>
      <LineNumber>1</LineNumber>
      <Description>Test1</Description>
      <Quantity>200</Quantity>
      <UnitPrice>500</UnitPrice>
      <Amounts>
        <Net>100000</Net>
        <VATRate>
          <Percent>2</Percent>
        </VATRate>
        <VATAmount>2000</VATAmount>
        <Gross>102000</Gross>
      </Amounts>
      <Extra>
        <ExchangeRate>1.5</ExchangeRate>
      </Extra>
    </Lines>
    <Lines>
      <LineNumber>2</LineNumber>
      <Description>Test2</Description>
      <Quantity>300</Quantity>
      <UnitPrice>1000</UnitPrice>
      <Amounts>
        <Net>300000</Net>
        <VATRate>
          <Percent>3</Percent>
        </VATRate>
        <VATAmount>9000</VATAmount>
        <Gross>309000</Gross>
      </Amounts>
      <Extra>
        <ExchangeRate>2</ExchangeRate>
      </Extra>
    </Lines>
    <Lines>
      <LineNumber>3</LineNumber>
      <Description>Test3</Description>
      <Quantity>100</Quantity>
      <UnitPrice>500</UnitPrice>
      <Amounts>
        <Net>50000</Net>
        <VATRate>
          <Percent>3</Percent>
        </VATRate>
        <VATAmount>1500</VATAmount>
        <Gross>51500</Gross>
      </Amounts>
      <Extra>
        <ExchangeRate>3</ExchangeRate>
      </Extra>
    </Lines>
    <Lines>
      <LineNumber>4</LineNumber>
      <Description>Test4</Description>
      <Quantity>100</Quantity>
      <UnitPrice>500</UnitPrice>
      <Amounts>
        <Net>50000</Net>
        <VATRate>
          <Excempt>0</Excempt>
        </VATRate>
        <VATAmount>0</VATAmount>
        <Gross>50000</Gross>
      </Amounts>
      <Extra>
        <ExchangeRate>1.2</ExchangeRate>
      </Extra>
    </Lines>
  </InvoiceLines>
</Document>

如您所见,Document/Header/ExchangeRate 部分和 Document/InvoiceLines/Lines/Extra/ExchangeRate

部分中都有一个 ExhangeRate 标签

如果 Document/InvoiceLines/Lines/Extra/ExchangeRate 部分不存在,它应该始终采用 Document/Header/ExchangeRate

中的值

但是对于下面的 XSLT1.0,它总是采用标记的第一个实例 Document/InvoiceLines/Lines/Extra/ExchangeRate:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:key name="amt-by-rate" match="Amounts" use="VATRate/*" />
  <xsl:variable name="Curr" select="//Header/Currency" />
  <xsl:decimal-format name="decFormat" decimal-separator="." grouping-separator="," NaN="0.00"/>
  <xsl:decimal-format name="XRFormat" decimal-separator="." grouping-separator="," NaN="1.00"/>

  <xsl:template match="Document">
    <Invoice>
      <xsl:apply-templates select ="Header" />
      <xsl:apply-templates select ="InvoiceLines" />
      <xsl:call-template name="Summary" />
    </Invoice>
  </xsl:template>

  <xsl:template match="InvoiceLines">
    <InvoiceDetails>
      <xsl:apply-templates select ="Lines" />
    </InvoiceDetails>

  </xsl:template>

  <xsl:template match ="Lines">
    <InvLine>
      <Number>
        <xsl:value-of select="LineNumber"/>
      </Number>
      <UnitPrice>
        <xsl:value-of select="Amount"/>
      </UnitPrice>
      <Quantity>
        <xsl:value-of select="Quantity"/>
      </Quantity>
      <Amounts>
        <xsl:copy-of select="Amounts/VATRate"/>
        <xsl:call-template name="Amounts">
          <xsl:with-param name="SectionName" select="'LineAmountData'" />
          <xsl:with-param name="FieldName" select="'LineAmount'" />
          <xsl:with-param name="Data" select="Amounts/Net" />
        </xsl:call-template>
        <xsl:call-template name="Amounts">
          <xsl:with-param name="SectionName" select="'LineVATData'" />
          <xsl:with-param name="FieldName" select="'VATAmount'" />
          <xsl:with-param name="Data" select="Amounts/VATAmount" />
        </xsl:call-template>
        <xsl:call-template name="Amounts">
          <xsl:with-param name="SectionName" select="'LineGrossData'" />
          <xsl:with-param name="FieldName" select="'GrossAmount'" />
          <xsl:with-param name="Data" select="Amounts/Gross" />
        </xsl:call-template>
      </Amounts>
    </InvLine>
  </xsl:template>

  <xsl:template name="Summary">
    <InvoiceSummary>
      <xsl:variable name="amounts" select="InvoiceLines/Lines/Amounts" />
      <Summary>
        <xsl:for-each select="$amounts[count(. | key('amt-by-rate', VATRate/*)[1]) = 1]">
          <xsl:variable name="current-group" select="key('amt-by-rate', VATRate/*)" />
          <Rate>
            <xsl:copy-of select="VATRate"/>
            <xsl:call-template name="Amounts">
              <xsl:with-param name="SectionName" select="'NetAmountData'" />
              <xsl:with-param name="FieldName" select="'NetAmount'" />
              <xsl:with-param name="Data" select="sum($current-group/Net)" />
            </xsl:call-template>
            <xsl:call-template name="Amounts">
              <xsl:with-param name="SectionName" select="'VATAmountData'" />
              <xsl:with-param name="FieldName" select="'VATAmount'" />
              <xsl:with-param name="Data" select="sum($current-group/VATAmount)" />
            </xsl:call-template>
            <xsl:call-template name="Amounts">
              <xsl:with-param name="SectionName" select="'GrossAmountData'" />
              <xsl:with-param name="FieldName" select="'GrossAmount'" />
              <xsl:with-param name="Data" select="sum($current-group/Gross)" />
            </xsl:call-template>
          </Rate>
        </xsl:for-each>
      </Summary>
      <xsl:call-template name="Amounts">
        <xsl:with-param name="SectionName" select="'InvoiceNetAmountData'" />
        <xsl:with-param name="FieldName" select="'InvoiceNetAmount'" />
        <xsl:with-param name="Data" select="sum($amounts/Net)" />
      </xsl:call-template>
      <xsl:call-template name="Amounts">
        <xsl:with-param name="SectionName" select="'InvoiceVATAmountData'" />
        <xsl:with-param name="FieldName" select="'InvoiceVATAmount'" />
        <xsl:with-param name="Data" select="sum($amounts/VATAmount)" />
      </xsl:call-template>
      <xsl:call-template name="Amounts">
        <xsl:with-param name="SectionName" select="'InvoiceGrossAmountData'" />
        <xsl:with-param name="FieldName" select="'InvoiceGrossAmount'" />
        <xsl:with-param name="Data" select="sum($amounts/Gross)" />
      </xsl:call-template>
    </InvoiceSummary>
  </xsl:template>

  <xsl:template match="Header">
    <InvoiceHeader>
      <Name>
        <xsl:value-of select="concat(FirstName,' ',LastName)" />
      </Name>
      <InvoiceDate>
        <xsl:value-of select="InvoiceDate" />
      </InvoiceDate>
      <InvoiceNumber>
        <xsl:value-of select="InvoiceNumber" />
      </InvoiceNumber>
    </InvoiceHeader>
  </xsl:template>

  <xsl:template name ="Amounts">
    <xsl:param name="SectionName" />
    <xsl:param name="FieldName" />
    <xsl:param name="DecimalPrecision" />
    <xsl:param name="Data" />

    <xsl:variable name="xRate">
      <xsl:choose>
        <xsl:when test="//Extra/ExchangeRate[position()]!=''">
          <xsl:value-of select ="format-number(//Extra/ExchangeRate,'#0.000','XRFormat')"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="format-number(//Header/ExchangeRate,'#0.000','XRFormat')"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>

    <xsl:choose>
      <xsl:when test="$SectionName!=''">
        <xsl:element name="{$SectionName}">
          <xsl:element name="{$FieldName}">
            <xsl:value-of select="format-number($Data, '#0.00' ,'decFormat')" />
          </xsl:element>
          <xsl:element name="{$FieldName}PHP">
            <xsl:value-of select="format-number($Data * $xRate, '#0.00','decFormat')" />
          </xsl:element>
        </xsl:element>
      </xsl:when>
      <xsl:otherwise>
        <xsl:element name="{$FieldName}">
          <xsl:value-of select="format-number($Data, '#0.00','decFormat')" />
        </xsl:element>
        <xsl:element name="{$FieldName}PHP">
          <xsl:value-of select="format-number($Data * $xRate, '#0.00','decFormat')" />
        </xsl:element>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

这是行和摘要部分的预期结果和当前错误结果:

任何人都可以帮助我确定这有什么问题。

提前致谢,顺便说一句,我需要使用 XSLT 1.0。

这是当前的 XML 结果:

<?xml version="1.0" encoding="utf-8"?>
<Invoice>
  <InvoiceHeader>
    <Name>Joel Cabarles</Name>
    <InvoiceDate>01-JAN-2020</InvoiceDate>
    <InvoiceNumber>123</InvoiceNumber>
  </InvoiceHeader>
  <InvoiceDetails>
    <InvLine>
      <Number>1</Number>
      <UnitPrice></UnitPrice>
      <Quantity>200</Quantity>
      <Amounts>
        <VATRate>
          <Percent>2</Percent>
        </VATRate>
        <LineAmountData>
          <LineAmount>100000.00</LineAmount>
          <LineAmountPHP>150000.00</LineAmountPHP>
        </LineAmountData>
        <LineVATData>
          <VATAmount>2000.00</VATAmount>
          <VATAmountPHP>3000.00</VATAmountPHP>
        </LineVATData>
        <LineGrossData>
          <GrossAmount>102000.00</GrossAmount>
          <GrossAmountPHP>153000.00</GrossAmountPHP>
        </LineGrossData>
      </Amounts>
    </InvLine>
    <InvLine>
      <Number>2</Number>
      <UnitPrice></UnitPrice>
      <Quantity>300</Quantity>
      <Amounts>
        <VATRate>
          <Percent>3</Percent>
        </VATRate>
        <LineAmountData>
          <LineAmount>300000.00</LineAmount>
          <LineAmountPHP>450000.00</LineAmountPHP>
        </LineAmountData>
        <LineVATData>
          <VATAmount>9000.00</VATAmount>
          <VATAmountPHP>13500.00</VATAmountPHP>
        </LineVATData>
        <LineGrossData>
          <GrossAmount>309000.00</GrossAmount>
          <GrossAmountPHP>463500.00</GrossAmountPHP>
        </LineGrossData>
      </Amounts>
    </InvLine>
    <InvLine>
      <Number>3</Number>
      <UnitPrice></UnitPrice>
      <Quantity>100</Quantity>
      <Amounts>
        <VATRate>
          <Percent>3</Percent>
        </VATRate>
        <LineAmountData>
          <LineAmount>50000.00</LineAmount>
          <LineAmountPHP>75000.00</LineAmountPHP>
        </LineAmountData>
        <LineVATData>
          <VATAmount>1500.00</VATAmount>
          <VATAmountPHP>2250.00</VATAmountPHP>
        </LineVATData>
        <LineGrossData>
          <GrossAmount>51500.00</GrossAmount>
          <GrossAmountPHP>77250.00</GrossAmountPHP>
        </LineGrossData>
      </Amounts>
    </InvLine>
    <InvLine>
      <Number>4</Number>
      <UnitPrice></UnitPrice>
      <Quantity>100</Quantity>
      <Amounts>
        <VATRate>
          <Excempt>0</Excempt>
        </VATRate>
        <LineAmountData>
          <LineAmount>50000.00</LineAmount>
          <LineAmountPHP>75000.00</LineAmountPHP>
        </LineAmountData>
        <LineVATData>
          <VATAmount>0.00</VATAmount>
          <VATAmountPHP>0.00</VATAmountPHP>
        </LineVATData>
        <LineGrossData>
          <GrossAmount>50000.00</GrossAmount>
          <GrossAmountPHP>75000.00</GrossAmountPHP>
        </LineGrossData>
      </Amounts>
    </InvLine>
  </InvoiceDetails>
  <InvoiceSummary>
    <Summary>
      <Rate>
        <VATRate>
          <Percent>2</Percent>
        </VATRate>
        <NetAmountData>
          <NetAmount>100000.00</NetAmount>
          <NetAmountPHP>150000.00</NetAmountPHP>
        </NetAmountData>
        <VATAmountData>
          <VATAmount>2000.00</VATAmount>
          <VATAmountPHP>3000.00</VATAmountPHP>
        </VATAmountData>
        <GrossAmountData>
          <GrossAmount>102000.00</GrossAmount>
          <GrossAmountPHP>153000.00</GrossAmountPHP>
        </GrossAmountData>
      </Rate>
      <Rate>
        <VATRate>
          <Percent>3</Percent>
        </VATRate>
        <NetAmountData>
          <NetAmount>350000.00</NetAmount>
          <NetAmountPHP>525000.00</NetAmountPHP>
        </NetAmountData>
        <VATAmountData>
          <VATAmount>10500.00</VATAmount>
          <VATAmountPHP>15750.00</VATAmountPHP>
        </VATAmountData>
        <GrossAmountData>
          <GrossAmount>360500.00</GrossAmount>
          <GrossAmountPHP>540750.00</GrossAmountPHP>
        </GrossAmountData>
      </Rate>
      <Rate>
        <VATRate>
          <Excempt>0</Excempt>
        </VATRate>
        <NetAmountData>
          <NetAmount>50000.00</NetAmount>
          <NetAmountPHP>75000.00</NetAmountPHP>
        </NetAmountData>
        <VATAmountData>
          <VATAmount>0.00</VATAmount>
          <VATAmountPHP>0.00</VATAmountPHP>
        </VATAmountData>
        <GrossAmountData>
          <GrossAmount>50000.00</GrossAmount>
          <GrossAmountPHP>75000.00</GrossAmountPHP>
        </GrossAmountData>
      </Rate>
    </Summary>
    <InvoiceNetAmountData>
      <InvoiceNetAmount>500000.00</InvoiceNetAmount>
      <InvoiceNetAmountPHP>750000.00</InvoiceNetAmountPHP>
    </InvoiceNetAmountData>
    <InvoiceVATAmountData>
      <InvoiceVATAmount>12500.00</InvoiceVATAmount>
      <InvoiceVATAmountPHP>18750.00</InvoiceVATAmountPHP>
    </InvoiceVATAmountData>
    <InvoiceGrossAmountData>
      <InvoiceGrossAmount>512500.00</InvoiceGrossAmount>
      <InvoiceGrossAmountPHP>768750.00</InvoiceGrossAmountPHP>
    </InvoiceGrossAmountData>
  </InvoiceSummary>
</Invoice>

这是预期的输出:

<?xml version="1.0" encoding="utf-8"?>
<Invoice>
  <InvoiceHeader>
    <Name>Joel Cabarles</Name>
    <InvoiceDate>01-JAN-2020</InvoiceDate>
    <InvoiceNumber>123</InvoiceNumber>
  </InvoiceHeader>
  <InvoiceDetails>
    <InvLine>
      <Number>1</Number>
      <UnitPrice></UnitPrice>
      <Quantity>200</Quantity>
      <Amounts>
        <VATRate>
          <Percent>2</Percent>
        </VATRate>
        <LineAmountData>
          <LineAmount>100000.00</LineAmount>
          <LineAmountPHP>150000.00</LineAmountPHP>
        </LineAmountData>
        <LineVATData>
          <VATAmount>2000.00</VATAmount>
          <VATAmountPHP>3000.00</VATAmountPHP>
        </LineVATData>
        <LineGrossData>
          <GrossAmount>102000.00</GrossAmount>
          <GrossAmountPHP>153000.00</GrossAmountPHP>
        </LineGrossData>
      </Amounts>
    </InvLine>
    <InvLine>
      <Number>2</Number>
      <UnitPrice></UnitPrice>
      <Quantity>300</Quantity>
      <Amounts>
        <VATRate>
          <Percent>3</Percent>
        </VATRate>
        <LineAmountData>
          <LineAmount>300000.00</LineAmount>
          <LineAmountPHP>600000.00</LineAmountPHP>
        </LineAmountData>
        <LineVATData>
          <VATAmount>9000.00</VATAmount>
          <VATAmountPHP>18000.00</VATAmountPHP>
        </LineVATData>
        <LineGrossData>
          <GrossAmount>309000.00</GrossAmount>
          <GrossAmountPHP>618000.00</GrossAmountPHP>
        </LineGrossData>
      </Amounts>
    </InvLine>
    <InvLine>
      <Number>3</Number>
      <UnitPrice></UnitPrice>
      <Quantity>100</Quantity>
      <Amounts>
        <VATRate>
          <Percent>3</Percent>
        </VATRate>
        <LineAmountData>
          <LineAmount>50000.00</LineAmount>
          <LineAmountPHP>150000.00</LineAmountPHP>
        </LineAmountData>
        <LineVATData>
          <VATAmount>1500.00</VATAmount>
          <VATAmountPHP>4500.00</VATAmountPHP>
        </LineVATData>
        <LineGrossData>
          <GrossAmount>51500.00</GrossAmount>
          <GrossAmountPHP>154500.00</GrossAmountPHP>
        </LineGrossData>
      </Amounts>
    </InvLine>
    <InvLine>
      <Number>4</Number>
      <UnitPrice></UnitPrice>
      <Quantity>100</Quantity>
      <Amounts>
        <VATRate>
          <Excempt>0</Excempt>
        </VATRate>
        <LineAmountData>
          <LineAmount>50000.00</LineAmount>
          <LineAmountPHP>60000.00</LineAmountPHP>
        </LineAmountData>
        <LineVATData>
          <VATAmount>0.00</VATAmount>
          <VATAmountPHP>0.00</VATAmountPHP>
        </LineVATData>
        <LineGrossData>
          <GrossAmount>50000.00</GrossAmount>
          <GrossAmountPHP>60000.00</GrossAmountPHP>
        </LineGrossData>
      </Amounts>
    </InvLine>
  </InvoiceDetails>
  <InvoiceSummary>
    <Summary>
      <Rate>
        <VATRate>
          <Percent>2</Percent>
        </VATRate>
        <NetAmountData>
          <NetAmount>100000.00</NetAmount>
          <NetAmountPHP>150000.00</NetAmountPHP>
        </NetAmountData>
        <VATAmountData>
          <VATAmount>2000.00</VATAmount>
          <VATAmountPHP>3000.00</VATAmountPHP>
        </VATAmountData>
        <GrossAmountData>
          <GrossAmount>102000.00</GrossAmount>
          <GrossAmountPHP>153000.00</GrossAmountPHP>
        </GrossAmountData>
      </Rate>
      <Rate>
        <VATRate>
          <Percent>3</Percent>
        </VATRate>
        <NetAmountData>
          <NetAmount>350000.00</NetAmount>
          <NetAmountPHP>750000.00</NetAmountPHP>
        </NetAmountData>
        <VATAmountData>
          <VATAmount>10500.00</VATAmount>
          <VATAmountPHP>22500.00</VATAmountPHP>
        </VATAmountData>
        <GrossAmountData>
          <GrossAmount>360500.00</GrossAmount>
          <GrossAmountPHP>772500.00</GrossAmountPHP>
        </GrossAmountData>
      </Rate>
      <Rate>
        <VATRate>
          <Excempt>0</Excempt>
        </VATRate>
        <NetAmountData>
          <NetAmount>50000.00</NetAmount>
          <NetAmountPHP>60000.00</NetAmountPHP>
        </NetAmountData>
        <VATAmountData>
          <VATAmount>0.00</VATAmount>
          <VATAmountPHP>0.00</VATAmountPHP>
        </VATAmountData>
        <GrossAmountData>
          <GrossAmount>50000.00</GrossAmount>
          <GrossAmountPHP>60000.00</GrossAmountPHP>
        </GrossAmountData>
      </Rate>
    </Summary>
    <InvoiceNetAmountData>
      <InvoiceNetAmount>500000.00</InvoiceNetAmount>
      <InvoiceNetAmountPHP>960000.00</InvoiceNetAmountPHP>
    </InvoiceNetAmountData>
    <InvoiceVATAmountData>
      <InvoiceVATAmount>12500.00</InvoiceVATAmount>
      <InvoiceVATAmountPHP>25500.00</InvoiceVATAmountPHP>
    </InvoiceVATAmountData>
    <InvoiceGrossAmountData>
      <InvoiceGrossAmount>512500.00</InvoiceGrossAmount>
      <InvoiceGrossAmountPHP>985500.00</InvoiceGrossAmountPHP>
    </InvoiceGrossAmountData>
  </InvoiceSummary>
</Invoice>

我认为不是

 <xsl:when test="//Extra/ExchangeRate[position()]!=''">

你更想要

 <xsl:when test="ancestor::Lines//Extra/ExchangeRate">
    <xsl:value-of select="format(ancestor::Lines//Extra/ExchangeRate, ...)"/>

我一次又一次地迷失在你命名的模板之后。但是因为这是你的风格,我已经对你的样式表进行了调整,你猜对了,再次添加命名模板。

看来你问题的核心在于xRate使用哪个。请关注评论解释。

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:key name="amt-by-rate" match="Amounts" use="VATRate/*" />
    <xsl:variable name="Curr" select="//Header/Currency" />
    <xsl:decimal-format name="decFormat" decimal-separator="." grouping-separator="," NaN="0.00"/>
    <xsl:decimal-format name="XRFormat" decimal-separator="." grouping-separator="," NaN="1.00"/>

    <xsl:template match="Document">
        <Invoice>
            <xsl:apply-templates select ="Header" />
            <xsl:apply-templates select ="InvoiceLines" />
            <xsl:call-template name="Summary" />
        </Invoice>
    </xsl:template>

    <xsl:template match="InvoiceLines">
        <InvoiceDetails>
            <xsl:apply-templates select ="Lines" />
        </InvoiceDetails>

    </xsl:template>

    <xsl:template match ="Lines">
        <!-- added an xRate variable here -->
        <xsl:variable name="xRate">
            <xsl:choose>
                <xsl:when test="Extra/ExchangeRate!=''">
                    <xsl:value-of select ="format-number(Extra/ExchangeRate,'#0.000','XRFormat')"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="format-number(//Header/ExchangeRate,'#0.000','XRFormat')"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:variable>
        <InvLine>
            <Number>
                <xsl:value-of select="LineNumber"/>
            </Number>
            <UnitPrice>
                <xsl:value-of select="Amount"/>
            </UnitPrice>
            <Quantity>
                <xsl:value-of select="Quantity"/>
            </Quantity>
            <Amounts>
                <xsl:copy-of select="Amounts/VATRate"/>
                <xsl:call-template name="Amounts">
                    <xsl:with-param name="SectionName" select="'LineAmountData'" />
                    <xsl:with-param name="FieldName" select="'LineAmount'" />
                    <xsl:with-param name="Data" select="Amounts/Net" />
                    <xsl:with-param name="xRate" select="$xRate" />
                </xsl:call-template>
                <xsl:call-template name="Amounts">
                    <xsl:with-param name="SectionName" select="'LineVATData'" />
                    <xsl:with-param name="FieldName" select="'VATAmount'" />
                    <xsl:with-param name="Data" select="Amounts/VATAmount" />
                    <xsl:with-param name="xRate" select="$xRate" />
                </xsl:call-template>
                <xsl:call-template name="Amounts">
                    <xsl:with-param name="SectionName" select="'LineGrossData'" />
                    <xsl:with-param name="FieldName" select="'GrossAmount'" />
                    <xsl:with-param name="Data" select="Amounts/Gross" />
                    <xsl:with-param name="xRate" select="$xRate" />
                </xsl:call-template>
            </Amounts>
        </InvLine>
    </xsl:template>

    <xsl:template name="Summary">
        <InvoiceSummary>
            <xsl:variable name="amounts" select="InvoiceLines/Lines/Amounts" />
            <Summary>
                <!-- group for each unique VATRate percentage -->
                <xsl:for-each select="$amounts[generate-id(.)=generate-id(key('amt-by-rate', VATRate/*)[1])]">
                    <!-- store each value of Net according to xRate -->
                    <xsl:variable name="each_Net">
                        <xsl:call-template name="xRate_times_net">
                            <xsl:with-param name="curr_VATRate" select="VATRate/*"/>
                        </xsl:call-template>
                    </xsl:variable>
                    <!-- convert the string to get a total value -->
                    <xsl:variable name="Net">
                        <xsl:call-template name="getCount">
                            <xsl:with-param name="str" select="$each_Net"/>
                            <xsl:with-param name="delimiter" select="','"/>
                        </xsl:call-template>
                    </xsl:variable>
                    <!-- same approach as above -->
                    <xsl:variable name="each_VAT">
                        <xsl:call-template name="xRate_times_VAT">
                            <xsl:with-param name="curr_VATRate" select="VATRate/*"/>
                        </xsl:call-template>
                    </xsl:variable>
                    <!-- same approach as above -->
                    <xsl:variable name="VAT">
                        <xsl:call-template name="getCount">
                            <xsl:with-param name="str" select="$each_VAT"/>
                            <xsl:with-param name="delimiter" select="','"/>
                        </xsl:call-template>
                    </xsl:variable>
                    <!-- same approach as above -->
                    <xsl:variable name="each_Gross">
                        <xsl:call-template name="xRate_times_Gross">
                            <xsl:with-param name="curr_VATRate" select="VATRate/*"/>
                        </xsl:call-template>
                    </xsl:variable>
                    <!-- same approach as above -->
                    <xsl:variable name="Gross">
                        <xsl:call-template name="getCount">
                            <xsl:with-param name="str" select="$each_Gross"/>
                            <xsl:with-param name="delimiter" select="','"/>
                        </xsl:call-template>
                    </xsl:variable>
                    <xsl:variable name="current-group" select="key('amt-by-rate', VATRate/*)" />
                    <Rate>
                        <xsl:copy-of select="VATRate"/>
                        <!-- this is a called template for grouped Summary -->
                        <xsl:call-template name="Amounts_Summary">
                            <xsl:with-param name="SectionName" select="'NetAmountData'" />
                            <xsl:with-param name="FieldName" select="'NetAmount'" />
                            <xsl:with-param name="Data" select="sum($current-group/Net)" />
                            <xsl:with-param name="Data_n_xRate" select="$Net" />
                        </xsl:call-template>
                        <xsl:call-template name="Amounts_Summary">
                            <xsl:with-param name="SectionName" select="'VATAmountData'" />
                            <xsl:with-param name="FieldName" select="'VATAmount'" />
                            <xsl:with-param name="Data" select="sum($current-group/VATAmount)" />
                            <xsl:with-param name="Data_n_xRate" select="$VAT" />
                        </xsl:call-template>
                        <xsl:call-template name="Amounts_Summary">
                            <xsl:with-param name="SectionName" select="'GrossAmountData'" />
                            <xsl:with-param name="FieldName" select="'GrossAmount'" />
                            <xsl:with-param name="Data" select="sum($current-group/Gross)" />
                            <xsl:with-param name="Data_n_xRate" select="$Gross" />
                        </xsl:call-template>
                    </Rate>
                </xsl:for-each>
            </Summary>
            <!-- the following shows the templates for the overall summary -->
            <xsl:variable name="all_Net">
                <xsl:for-each select="//Amounts/Net">
                    <xsl:variable name="xRate">
                        <xsl:choose>
                            <xsl:when test="../following-sibling::Extra/ExchangeRate!=''">
                                <xsl:value-of select ="format-number(../following-sibling::Extra/ExchangeRate,'#0.000','XRFormat')"/>
                            </xsl:when>
                            <xsl:otherwise>
                                <xsl:value-of select="format-number(//Header/ExchangeRate,'#0.000','XRFormat')"/>
                            </xsl:otherwise>
                        </xsl:choose>
                    </xsl:variable>
                    <xsl:if test="position()&gt;1">
                        <xsl:text>,</xsl:text>
                    </xsl:if>
                    <xsl:value-of select=".*$xRate"/>
                </xsl:for-each>
            </xsl:variable>
            <xsl:variable name="sum_Net">
                <xsl:call-template name="getCount">
                    <xsl:with-param name="str" select="$all_Net"/>
                    <xsl:with-param name="delimiter" select="','"/>
                </xsl:call-template>
            </xsl:variable>
            <xsl:variable name="all_VAT">
                <xsl:for-each select="//Amounts/VATAmount">
                    <xsl:variable name="xRate">
                        <xsl:choose>
                            <xsl:when test="../following-sibling::Extra/ExchangeRate!=''">
                                <xsl:value-of select ="format-number(../following-sibling::Extra/ExchangeRate,'#0.000','XRFormat')"/>
                            </xsl:when>
                            <xsl:otherwise>
                                <xsl:value-of select="format-number(//Header/ExchangeRate,'#0.000','XRFormat')"/>
                            </xsl:otherwise>
                        </xsl:choose>
                    </xsl:variable>
                    <xsl:if test="position()&gt;1">
                        <xsl:text>,</xsl:text>
                    </xsl:if>
                    <xsl:value-of select=".*$xRate"/>
                </xsl:for-each>
            </xsl:variable>
            <xsl:variable name="sum_VAT">
                <xsl:call-template name="getCount">
                    <xsl:with-param name="str" select="$all_VAT"/>
                    <xsl:with-param name="delimiter" select="','"/>
                </xsl:call-template>
            </xsl:variable>
            <xsl:variable name="all_Gross">
                <xsl:for-each select="//Amounts/Gross">
                    <xsl:variable name="xRate">
                        <xsl:choose>
                            <xsl:when test="../following-sibling::Extra/ExchangeRate!=''">
                                <xsl:value-of select ="format-number(../following-sibling::Extra/ExchangeRate,'#0.000','XRFormat')"/>
                            </xsl:when>
                            <xsl:otherwise>
                                <xsl:value-of select="format-number(//Header/ExchangeRate,'#0.000','XRFormat')"/>
                            </xsl:otherwise>
                        </xsl:choose>
                    </xsl:variable>
                    <xsl:if test="position()&gt;1">
                        <xsl:text>,</xsl:text>
                    </xsl:if>
                    <xsl:value-of select=".*$xRate"/>
                </xsl:for-each>
            </xsl:variable>
            <xsl:variable name="sum_Gross">
                <xsl:call-template name="getCount">
                    <xsl:with-param name="str" select="$all_Gross"/>
                    <xsl:with-param name="delimiter" select="','"/>
                </xsl:call-template>
            </xsl:variable>
            <xsl:call-template name="Amounts_Summary">
                <xsl:with-param name="SectionName" select="'InvoiceNetAmountData'" />
                <xsl:with-param name="FieldName" select="'InvoiceNetAmount'" />
                <xsl:with-param name="Data" select="sum($amounts/Net)" />
                <xsl:with-param name="Data_n_xRate" select="$sum_Net" />
            </xsl:call-template>
            <xsl:call-template name="Amounts_Summary">
                <xsl:with-param name="SectionName" select="'InvoiceVATAmountData'" />
                <xsl:with-param name="FieldName" select="'InvoiceVATAmount'" />
                <xsl:with-param name="Data" select="sum($amounts/VATAmount)" />
                <xsl:with-param name="Data_n_xRate" select="$sum_VAT" />
            </xsl:call-template>
            <xsl:call-template name="Amounts_Summary">
                <xsl:with-param name="SectionName" select="'InvoiceGrossAmountData'" />
                <xsl:with-param name="FieldName" select="'InvoiceGrossAmount'" />
                <xsl:with-param name="Data" select="sum($amounts/Gross)" />
                <xsl:with-param name="Data_n_xRate" select="$sum_Gross" />
            </xsl:call-template>
        </InvoiceSummary>
    </xsl:template>

    <xsl:template match="Header">
        <InvoiceHeader>
            <Name>
                <xsl:value-of select="concat(FirstName,' ',LastName)" />
            </Name>
            <InvoiceDate>
                <xsl:value-of select="InvoiceDate" />
            </InvoiceDate>
            <InvoiceNumber>
                <xsl:value-of select="InvoiceNumber" />
            </InvoiceNumber>
        </InvoiceHeader>
    </xsl:template>

    <xsl:template name ="Amounts">
        <xsl:param name="SectionName" />
        <xsl:param name="FieldName" />
        <xsl:param name="DecimalPrecision" />
        <xsl:param name="Data" />
        <xsl:param name="xRate" />

        <xsl:choose>
            <xsl:when test="$SectionName!=''">
                <xsl:element name="{$SectionName}">
                    <xsl:element name="{$FieldName}">
                        <xsl:value-of select="format-number($Data, '#0.00' ,'decFormat')" />
                    </xsl:element>
                    <xsl:element name="{$FieldName}PHP">
                        <xsl:value-of select="format-number($Data * $xRate, '#0.00','decFormat')" />
                    </xsl:element>
                </xsl:element>
            </xsl:when>
            <xsl:otherwise>
                <xsl:element name="{$FieldName}">
                    <xsl:value-of select="format-number($Data, '#0.00','decFormat')" />
                </xsl:element>
                <xsl:element name="{$FieldName}PHP">
                    <xsl:value-of select="format-number($Data * $xRate, '#0.00','decFormat')" />
                </xsl:element>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <xsl:template name ="Amounts_Summary">
        <xsl:param name="SectionName" />
        <xsl:param name="FieldName" />
        <xsl:param name="DecimalPrecision" />
        <xsl:param name="Data" />
        <xsl:param name="Data_n_xRate" />

        <xsl:choose>
            <xsl:when test="$SectionName!=''">
                <xsl:element name="{$SectionName}">
                    <xsl:element name="{$FieldName}">
                        <xsl:value-of select="format-number($Data, '#0.00' ,'decFormat')" />
                    </xsl:element>
                    <xsl:element name="{$FieldName}PHP">
                        <xsl:value-of select="format-number($Data_n_xRate, '#0.00','decFormat')" />
                    </xsl:element>
                </xsl:element>
            </xsl:when>
            <xsl:otherwise>
                <xsl:element name="{$FieldName}">
                    <xsl:value-of select="format-number($Data, '#0.00','decFormat')" />
                </xsl:element>
                <xsl:element name="{$FieldName}PHP">
                    <xsl:value-of select="format-number($Data_n_xRate, '#0.00','decFormat')" />
                </xsl:element>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <xsl:template name="xRate_times_net">
        <xsl:param name="curr_VATRate"/>
        <xsl:for-each select="key('amt-by-rate', $curr_VATRate)">
            <xsl:variable name="xRate">
                <xsl:choose>
                    <xsl:when test="following-sibling::Extra/ExchangeRate!=''">
                        <xsl:value-of select ="format-number(following-sibling::Extra/ExchangeRate,'#0.000','XRFormat')"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="format-number(//Header/ExchangeRate,'#0.000','XRFormat')"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:variable>
            <xsl:if test="position()&gt;1">
                <xsl:text>,</xsl:text>
            </xsl:if>
            <xsl:value-of select="Net*$xRate"/>
        </xsl:for-each>
    </xsl:template>

    <xsl:template name="xRate_times_VAT">
        <xsl:param name="curr_VATRate"/>
        <xsl:for-each select="key('amt-by-rate', VATRate/*)">
            <xsl:variable name="xRate">
                <xsl:choose>
                    <xsl:when test="following-sibling::Extra/ExchangeRate!=''">
                        <xsl:value-of select ="format-number(following-sibling::Extra/ExchangeRate,'#0.000','XRFormat')"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="format-number(//Header/ExchangeRate,'#0.000','XRFormat')"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:variable>
            <xsl:if test="position()&gt;1">
                <xsl:text>,</xsl:text>
            </xsl:if>
            <xsl:value-of select="VATAmount*$xRate"/>
        </xsl:for-each>
    </xsl:template>

    <xsl:template name="xRate_times_Gross">
        <xsl:param name="curr_VATRate"/>
        <xsl:for-each select="key('amt-by-rate', VATRate/*)">
            <xsl:variable name="xRate">
                <xsl:choose>
                    <xsl:when test="following-sibling::Extra/ExchangeRate!=''">
                        <xsl:value-of select ="format-number(following-sibling::Extra/ExchangeRate,'#0.000','XRFormat')"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="format-number(//Header/ExchangeRate,'#0.000','XRFormat')"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:variable>
            <xsl:if test="position()&gt;1">
                <xsl:text>,</xsl:text>
            </xsl:if>
            <xsl:value-of select="Gross*$xRate"/>
        </xsl:for-each>
    </xsl:template>

    <xsl:template name="getCount" >
        <xsl:param name="str" />
        <xsl:param name="delimiter" />
        <xsl:param name="summation" select="0" />
        <xsl:choose>
            <xsl:when test="contains($str,$delimiter)">
                <xsl:variable name="beforecomma" select="substring-before($str,$delimiter)" />
                <xsl:variable name="aftercomma" select="substring-after($str,$delimiter)" />
                <xsl:call-template name="getCount">
                    <xsl:with-param name="str" select="$aftercomma" />
                    <xsl:with-param name="delimiter" select="$delimiter" />
                    <xsl:with-param name="summation" select="$summation + $beforecomma" />
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$summation + $str" />
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

看到它在这里工作:http://xsltransform.net/93FbieK