如何在XSLT

时间:2018-03-28 12:38:52

标签: xml xslt count xslt-1.0 xslt-2.0

我有一个包含工人和金额的XML。在输出中,文件将包含一个工人的行 - 如果他有EX则为一行,如果他有ER则为一行。如果他在xml文件中有amount1,他有EX,如果他有amount2,他有ER。这在我目前的XSLT中运行得非常好。

主要问题是如何在分组后正确获取正确的总行数和所有金额(金额1和金额2)的总和,并应添加到标题中。

这是示例XML:

<Report_Data>
<Report_Entry>
    <Worker>
        <Name>User1</Name>            
        <ID>1234</ID>
    </Worker>
    <amount1>-200</amount1>
    <amount2>100</amount2> 
</Report_Entry>    
<Report_Entry>
    <Worker>
        <Name>User1</Name>           
        <ID>1234</ID>
    </Worker>
    <amount1>100</amount1>
    <amount2>-50</amount2> 
</Report_Entry>
<Report_Entry>
    <Worker>
        <Name>User2</Name>            
        <ID>5678</ID>
    </Worker>
    <amount1>-20</amount1>  
    <amount2>100</amount2>         
</Report_Entry>
<Report_Entry>
    <Worker>
        <Name>User1</Name>            
        <ID>1234</ID>
    </Worker>
    <amount1>0</amount1>
    <amount2>0</amount2> 
</Report_Entry>  
</Report_Data>


这是我的样本XSLT(我在柜台上工作,但不能正确。尝试了很多,但我最终得到了变量的计数,但它得到所有的行而不是3.我认为它是因为当前组看起来xml上的所有行值...):

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
xmlns:saxon="http://saxon.sf.net/" xmlns:ns0="urn:com.foo" extension-element-prefixes="saxon"
version="2.0">

<xsl:output method="text"/>


<xsl:variable name="SumOfAmount1" saxon:assignable="yes"/>
<xsl:variable name="SumOfAmount2" saxon:assignable="yes"/>

<xsl:variable name="countEX" as="xs:string*">
    <xsl:for-each-group select="Report_Data/Report_Entry" group-by="Worker/ID">

        <saxon:assign name="SumOfAmount1" select="sum(current-group()/Report_Data/Report_Entry/amount1)"/>            
        <xsl:if test="$SumOfAmount1 >= 0.00">
            <xsl:sequence select="current-group()"></xsl:sequence>

        </xsl:if>     

    </xsl:for-each-group>          
</xsl:variable>
<xsl:variable name="countER" as="xs:string*">
    <xsl:for-each-group select="/Report_Data/wd:Report_Entry" group-by="ID">

        <saxon:assign name="SumOfAmount1" select="sum(current-group()/Report_Data/Report_Entry/amount2)"/>            
        <xsl:if test="$SumOfAmount1 >= 0.00">
            <xsl:sequence select="current-group()"></xsl:sequence>                
        </xsl:if>     

    </xsl:for-each-group>          
</xsl:variable>


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

<xsl:template match="Report_Data">        

    <Header>
        <!--Total count of rows!-->
         //add countER and countEX
        <xsl:text>,</xsl:text>
        <!--Sum of amount1 and amount2 !-->
        //add total amounts 

    </Header>
    <ReportData>

        <xsl:for-each-group select="Report_Entry" group-by="Worker/ID">
            <ReportEntry>                                            
                <xsl:copy-of select="current-group()[1]/*[starts-with(name(), 'ID')]"/>
            </ReportEntry>

            <saxon:assign name="SumOfAmount1" select="sum(current-group()/amount1)"/>
            <saxon:assign name="SumOfAmount2" select="sum(current-group()/amount2)"/>


            <xsl:if test="$SumOfAmount1 >= 0.00">
                <xsl:call-template name="EX"></xsl:call-template>                    
            </xsl:if>
            <xsl:if test="$SumOfAmount2 >= 0.00">                                       
                <xsl:call-template name="ER"></xsl:call-template>                                                               
            </xsl:if>                                   

        </xsl:for-each-group>

    </ReportData>

</xsl:template>

<xsl:template name="EX">              
    <Name>
        <xsl:value-of select="Worker/Name"/>
    </Name>
    <xsl:text>,</xsl:text>
    <ID>
        <xsl:value-of select="Worker/ID"/>
    </ID>
    <xsl:text>,</xsl:text>        
    <amount1>            
        <xsl:value-of select="$SumOfAmount1"/>            
    </amount1>
    <xsl:text>,</xsl:text>                                                       
    <xsl:value-of select="'EX'"></xsl:value-of>        
    <xsl:value-of select="'&#xa;'"></xsl:value-of>            
</xsl:template>

<xsl:template name="ER">         
    <Name>
        <xsl:value-of select="Worker/Name"/>
    </Name>
    <xsl:text>,</xsl:text>
    <ID>
        <xsl:value-of select="Worker/ID"/>
    </ID>
    <xsl:text>,</xsl:text>        
    <amount1>            
        <xsl:value-of select="$SumOfAmount2"/>            
    </amount1>
    <xsl:text>,</xsl:text>                                                       
    <xsl:value-of select="'ER'"></xsl:value-of>        
    <xsl:value-of select="'&#xa;'"></xsl:value-of>                                                                                            
</xsl:template>

</xsl:stylesheet>

预期产出:

 2,150
 User1,1234,50,ER
 User2,5678,100,ER

其中:2是行数,150是所有金额(amount1和amount2)的总和。

P.S。负数不包含在文件中。如果amount1或amount2为负数,则它们仍包含在添加中,但如果总和为负数,则将被排除,不会显示在文件中。

感谢您的帮助。

1 个答案:

答案 0 :(得分:2)

我会按ID分组一次,然后根据是否有amount1/amount2元素存储行数据。为了计算总和,我只需再次选择元素:

  <xsl:template match="/">
      <xsl:variable name="rows" as="element(row)*">
         <xsl:for-each-group select="Report_Data/Report_Entry" group-by="Worker/ID">
             <xsl:if test="current-group()/amount1">
                 <row>
                     <xsl:value-of select="Worker/Name, current-grouping-key(), sum(current-group()/amount1), 'EX'" separator=","/>
                 </row>
             </xsl:if>
             <xsl:if test="current-group()/amount2">
                 <row>
                     <xsl:value-of select="Worker/Name, current-grouping-key(), sum(current-group()/amount2), 'ER'" separator=","/>
                 </row>
             </xsl:if>
        </xsl:for-each-group>
      </xsl:variable>
      <xsl:value-of select="count($rows), sum(Report_Data/Report_Entry/*[starts-with(local-name(), 'amount')]), $rows" separator="&#10;"/>
  </xsl:template>

http://xsltfiddle.liberty-development.net/bdxtpA

似乎我没有完全正确的格式,请参阅http://xsltfiddle.liberty-development.net/bdxtpA/1了解使用

的更正
  <xsl:value-of select="concat(count($rows), ',', sum(Report_Data/Report_Entry/*[starts-with(local-name(), 'amount')])), $rows" separator="&#10;"/>

对于消除总和金额为负数的群体的精细要求,我认为

  <xsl:template match="/">
      <xsl:variable name="rows" as="element(row)*">
         <xsl:for-each-group select="Report_Data/Report_Entry" group-by="Worker/ID">
             <xsl:variable name="sum1" select="sum(current-group()/amount1)"/>
             <xsl:if test="current-group()/amount1 and $sum1 > 0">
                 <row sum="{$sum1}">
                     <xsl:value-of select="Worker/Name, current-grouping-key(), $sum1, 'EX'" separator=","/>
                 </row>
             </xsl:if>
             <xsl:variable name="sum2" select="sum(current-group()/amount2)"/>
             <xsl:if test="current-group()/amount2 and $sum2 > 0">
                 <row sum="{$sum2}">
                     <xsl:value-of select="Worker/Name, current-grouping-key(), $sum2, 'ER'" separator=","/>
                 </row>
             </xsl:if>
        </xsl:for-each-group>
      </xsl:variable>
      <xsl:value-of select="concat(count($rows), ',', sum($rows/@sum)), $rows" separator="&#10;"/>
  </xsl:template>

这样做:http://xsltfiddle.liberty-development.net/bdxtpA/2