XSLT总和(多个条件)

时间:2013-07-08 16:00:04

标签: xslt

我使用XSLT : Cummulative Sum (Conditional)的答案作为“基础”来对不同的xml进行求和,而我得不到正确的总和。

应仅为Root / Items / Result / Sku中的'skus'创建输出。对于Root / Providers / Result /

中唯一的提供者,累计和应按“提供者质量”(主要,损坏)分组

我确信总和中的谓词条件是错误的。但我无法弄清楚这个问题。我将不胜感激任何帮助。谢谢!

示例XML:

<?xml version="1.0" encoding="UTF-8"?>
<Root>
    <Items>
        <Result>
            <Sku>XYZ</Sku>
        </Result>
        <Result>
            <Sku>ABC</Sku>
        </Result>
    </Items>
    <Providers>
        <Result>
            <ProviderCode>1_M</ProviderCode>
            <Quality>Main</Quality>
        </Result>
        <Result>
            <ProviderCode>1_D</ProviderCode>
            <Quality>Damaged</Quality>
        </Result>
        <Result>
            <ProviderCode>2_M</ProviderCode>
            <Quality>Main</Quality>
        </Result>
        <Result>
            <ProviderCode>2_D</ProviderCode>
            <Quality>Damaged</Quality>
        </Result>
    </Providers>
    <Message>
        <Body>
            <Inventory>
                <SKU>
                    <SKU>AXYZ</SKU>
                    <Description>XYZ Description</Description>
                    <Providers>
                        <Provider>
                            <ProviderCode>1_M</ProviderCode>
                            <Qty>100</Qty>
                        </Provider>
                        <Provider>
                            <ProviderCode>2_M</ProviderCode>
                            <Qty>67</Qty>
                        </Provider>
                        <Provider>
                            <ProviderCode>2_D</ProviderCode>
                            <Qty>75</Qty>
                        </Provider>                        
                        <Provider>
                            <ProviderCode>3_M</ProviderCode>
                            <Qty>74</Qty>
                        </Provider>
                        <Provider>
                            <ProviderCode>4</ProviderCode>
                            <Qty>62</Qty>
                        </Provider>    
                    </Providers>
                </SKU>
                <SKU>
                    <SKU>ABC</SKU>
                    <Description>ABC Description</Description>
                    <Providers>
                        <Provider>
                            <ProviderCode>1_M</ProviderCode>
                            <Qty>20</Qty>
                        </Provider>
                        <Provider>
                            <ProviderCode>1_D</ProviderCode>
                            <Qty>205</Qty>
                        </Provider>
                        <Provider>
                            <ProviderCode>2_M</ProviderCode>
                            <Qty>77</Qty>
                        </Provider>
                        <Provider>
                            <ProviderCode>2_D</ProviderCode>
                            <Qty>5</Qty>
                        </Provider>                        
                        <Provider>
                            <ProviderCode>3_M</ProviderCode>
                            <Qty>42</Qty>
                        </Provider>    
                        <Provider>
                            <ProviderCode>4_M</ProviderCode>
                            <Qty>631</Qty>
                        </Provider>    
                    </Providers>
                </SKU>    
            </Inventory>
        </Body>
    </Message>
</Root>

使用XSLT:          

    <xsl:output  method="xml" indent="yes"/>
    <xsl:key name="validProviders" match="/Root/Providers/Result" use="ProviderCode"/>
    <xsl:key name="validProviderQuality" match="/Root/Providers/Result" use="Quality"/>
    <xsl:key name="inboundSkus" match="/Root/Message/Body/Inventory/SKU" use="SKU"/>

    <xsl:template match="/">
        <Root>
            <xsl:apply-templates select="/Root/Items/Result"/>
        </Root>
    </xsl:template>

    <xsl:template match="/Root/Items/Result">
        <xsl:if test="key('inboundSkus',Sku)">
            <SKU>
                <xsl:variable name="Sku" select="Sku"/>
                <xsl:for-each select="/Root/Providers/Result[generate-id(.)=generate-id(key('validProviderQuality',Quality)[1])]">
                    <Record>
                        <xsl:variable name="ProviderQuality" select="Quality" />
                        <xsl:element name="Sku"><xsl:value-of select="$Sku"/></xsl:element>
                        <xsl:element name="Quality"><xsl:value-of select="$ProviderQuality"/></xsl:element>
                        <xsl:element name="Qty1"><xsl:value-of select="sum(/Root/Message/Body/Inventory/SKU[SKU=$Sku]/Providers/Provider[ProviderCode=/Root/Providers/Result[Quality=$ProviderQuality]]/Qty)"/></xsl:element>
                        <xsl:element name="Qty2"><xsl:value-of select="sum(/Root/Message/Body/Inventory/SKU[SKU=$Sku]/Providers/Provider[key('validProviderQuality',$ProviderQuality)]/Qty)"/></xsl:element>
                    </Record>                        
                </xsl:for-each>
            </SKU>
        </xsl:if>
    </xsl:template>

</xsl:stylesheet>

输出:

<?xml version="1.0" encoding="utf-8"?>
<Root>
    <SKU>
        <Record>
            <Sku>ABC</Sku>
            <Quality>Main</Quality>
            <Qty1>0</Qty1>
            <Qty2>980</Qty2>
        </Record>
        <Record>
            <Sku>ABC</Sku>
            <Quality>Damaged</Quality>
            <Qty1>0</Qty1>
            <Qty2>980</Qty2>
        </Record>
    </SKU>
</Root>

通缉结果

<Root>
  <SKU>
    <Record>
      <Sku>ABC</Sku>
      <Quality>Main</Quality>
      <Qty>97</Qty>
    </Record>
    <Record>
      <Sku>ABC</Sku>
      <Quality>Damaged</Quality>
      <Qty>210</Qty>
    </Record>
  </SKU>
</Root>

2 个答案:

答案 0 :(得分:0)

我认为这个要求非常复杂,为了更好地理解它,我试图在XSLT 2.0中实现它。我没有时间尝试在XSLT 1.0中实现它,所以我将发布XSLT 2.0代码(你可以运行像Saxon 9或AltovaXML这样的XSLT 2.0处理器):

<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 indent="yes"/>

<xsl:variable name="wanted-skus" select="/Root/Items/Result/Sku"/>

<xsl:variable name="wanted-prvdrs" select="/Root/Providers/Result/ProviderCode"/>

<xsl:key name="qual" match="Root/Providers/Result" use="ProviderCode"/>

<xsl:template match="Root">
  <xsl:copy>
    <xsl:for-each-group 
     select="Message/Body/Inventory/SKU
              [SKU = $wanted-skus]
              /Providers/Provider[ProviderCode = $wanted-prvdrs]"
          group-by="key('qual', ProviderCode)/Quality">      
           <Record>
             <Sku><xsl:value-of select="ancestor::SKU/SKU"/></Sku>
             <Quality><xsl:value-of select="current-grouping-key()"/></Quality>
             <Qty><xsl:value-of select="sum(current-group()/Qty)"/></Qty>
           </Record>
    </xsl:for-each-group>
  </xsl:copy>
</xsl:template>       

</xsl:stylesheet>

使用该样式表Saxon 9.5转换输入

<?xml version="1.0" encoding="UTF-8"?>
<Root>
    <Items>
        <Result>
            <Sku>XYZ</Sku>
        </Result>
        <Result>
            <Sku>ABC</Sku>
        </Result>
    </Items>
    <Providers>
        <Result>
            <ProviderCode>1_M</ProviderCode>
            <Quality>Main</Quality>
        </Result>
        <Result>
            <ProviderCode>1_D</ProviderCode>
            <Quality>Damaged</Quality>
        </Result>
        <Result>
            <ProviderCode>2_M</ProviderCode>
            <Quality>Main</Quality>
        </Result>
        <Result>
            <ProviderCode>2_D</ProviderCode>
            <Quality>Damaged</Quality>
        </Result>
    </Providers>
    <Message>
        <Body>
            <Inventory>
                <SKU>
                    <SKU>AXYZ</SKU>
                    <Description>XYZ Description</Description>
                    <Providers>
                        <Provider>
                            <ProviderCode>1_M</ProviderCode>
                            <Qty>100</Qty>
                        </Provider>
                        <Provider>
                            <ProviderCode>2_M</ProviderCode>
                            <Qty>67</Qty>
                        </Provider>
                        <Provider>
                            <ProviderCode>2_D</ProviderCode>
                            <Qty>75</Qty>
                        </Provider>                        
                        <Provider>
                            <ProviderCode>3_M</ProviderCode>
                            <Qty>74</Qty>
                        </Provider>
                        <Provider>
                            <ProviderCode>4</ProviderCode>
                            <Qty>62</Qty>
                        </Provider>    
                    </Providers>
                </SKU>
                <SKU>
                    <SKU>ABC</SKU>
                    <Description>ABC Description</Description>
                    <Providers>
                        <Provider>
                            <ProviderCode>1_M</ProviderCode>
                            <Qty>20</Qty>
                        </Provider>
                        <Provider>
                            <ProviderCode>1_D</ProviderCode>
                            <Qty>205</Qty>
                        </Provider>
                        <Provider>
                            <ProviderCode>2_M</ProviderCode>
                            <Qty>77</Qty>
                        </Provider>
                        <Provider>
                            <ProviderCode>2_D</ProviderCode>
                            <Qty>5</Qty>
                        </Provider>                        
                        <Provider>
                            <ProviderCode>3_M</ProviderCode>
                            <Qty>42</Qty>
                        </Provider>    
                        <Provider>
                            <ProviderCode>4_M</ProviderCode>
                            <Qty>631</Qty>
                        </Provider>    
                    </Providers>
                </SKU>    
            </Inventory>
        </Body>
    </Message>
</Root>

进入想要的结果

<Root>
   <Record>
      <Sku>ABC</Sku>
      <Quality>Main</Quality>
      <Qty>97</Qty>
   </Record>
   <Record>
      <Sku>ABC</Sku>
      <Quality>Damaged</Quality>
      <Qty>210</Qty>
   </Record>
</Root>

答案 1 :(得分:0)

这里将样式表改编为xslt-1.0解决方案。 你可以试试这个:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output  method="xml" indent="yes"/>
    <xsl:key name="validProviderQuality" match="/Root/Providers/Result" use="Quality"/>

    <xsl:variable name="mySkus" select="//Result/Sku" />
    <xsl:template match="/">
        <Root>
            <xsl:apply-templates 
                   select="/Root/Message/Body/Inventory/SKU[SKU = $mySkus]"/>
        </Root>
    </xsl:template>

    <xsl:template match="/Root/Message/Body/Inventory/SKU" >

        <xsl:variable name="Sku" select="SKU"/>
        <xsl:for-each select="/Root/Providers/Result[generate-id(.)= 
                                  generate-id(key('validProviderQuality',Quality)[1])]">
            <SKU>
                <Record>
                    <xsl:variable name="ProviderQuality" select="Quality" />
                    <xsl:element name="Sku">
                        <xsl:value-of select="$Sku"/>
                    </xsl:element>
                    <xsl:element name="Quality">
                        <xsl:value-of select="$ProviderQuality"/>
                    </xsl:element>
                    <xsl:element name="Qty">
                        <xsl:value-of 
                           select="sum(//SKU[SKU=$Sku]//Provider[
                                          ProviderCode=/Root/Providers/Result[
                                            Quality=$ProviderQuality
                                          ]/ProviderCode
                                        ]/Qty)"/>
                    </xsl:element>
                </Record>
            </SKU>
        </xsl:for-each>
    </xsl:template>

</xsl:stylesheet>

将生成以下输出:

<?xml version="1.0"?>
<Root>
  <SKU>
    <Record>
      <Sku>ABC</Sku>
      <Quality>Main</Quality>
      <Qty>97</Qty>
    </Record>
  </SKU>
  <SKU>
    <Record>
      <Sku>ABC</Sku>
      <Quality>Damaged</Quality>
      <Qty>210</Qty>
    </Record>
  </SKU>
</Root>