2013-04-27 252 views
1

我是XSLT的初学者,对于Muenchian分组方法感到困惑。 这里是我的XML文档如何使用Muenchian方法对父属性进行分组?

<?xml version='1.0'?> 
<?xml-stylesheet type="text/xsl" href="test.xslt"?> 
<catalog> 
    <cd PurchaseDate="20000101"> 
     <title>Empire Burlesque</title> 
     <artist>Bob Dylan</artist> 
     <country>USA</country> 
     <quantity>20</quantity> 
     <price>10.90</price> 
    </cd> 
    <cd PurchaseDate="20000101"> 
     <title>Hide your heart</title> 
     <artist>Bonnie Tyler</artist> 
     <country>UK</country> 
     <quantity>10</quantity> 
     <price>9.90</price> 
    </cd> 
    <cd PurchaseDate="20000102"> 
     <title>Greatest Hits</title> 
     <artist>Dolly Parton</artist> 
     <country>USA</country> 
     <quantity>15</quantity> 
     <price>9.90</price> 
    </cd> 
    <cd PurchaseDate="20000101"> 
     <title>Still got the blues</title> 
     <artist>Gary Moore</artist> 
     <country>UK</country> 
     <quantity>5</quantity> 
     <price>10.20</price> 
    </cd> 
    <cd PurchaseDate="20000103"> 
     <title>Eros</title> 
     <artist>Eros Ramazzotti</artist> 
     <country>EU</country> 
     <quantity>6</quantity> 
     <price>9.90</price> 
    </cd> 
    <cd PurchaseDate="20000103"> 
     <title>One night only</title> 
     <artist>Bee Gees</artist> 
     <country>UK</country> 
     <quantity>16</quantity> 
     <price>10.90</price> 
    </cd> 
    <cd PurchaseDate="20000102"> 
     <title>Sylvias Mother</title> 
     <artist>Dr.Hook</artist> 
     <country>UK</country> 
     <quantity>3</quantity> 
     <price>8.10</price> 
    </cd> 
    <cd PurchaseDate="20000101"> 
     <title>Maggie May</title> 
     <artist>Rod Stewart</artist> 
     <country>UK</country> 
     <quantity>8</quantity> 
     <price>8.50</price> 
    </cd> 
    <cd PurchaseDate="20000103"> 
     <title>Romanza</title> 
     <artist>Andrea Bocelli</artist> 
     <country>EU</country> 
     <quantity>30</quantity> 
     <price>10.80</price> 
    </cd> 
</catalog> 

和XSLT

<?xml version="1.0"?> 
<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" version="1.0" indent="yes" /> 
    <xsl:key name="kByCountry" match="cd" use="country" /> 
    <xsl:output method="html" /> 
    <xsl:template match="catalog"> 
     <html> 
      <body> 
       <table border="1"> 
        <xsl:for-each select="cd[count(.|key('kByCountry',country)[1]) = 1]"> 
         <xsl:sort select="country" /> 
         <tr bgcolor="#9acd32"> 
          <td colspan="4">Country:<xsl:value-of select="country" /></td> 
         </tr> 
         <tr> 
          <td>Purchase Date</td> 
          <td>Quantity</td> 
          <td>Unit Price</td> 
          <td>Total</td> 
         </tr> 
         <tr> 
          <td>?date?</td> 
          <td><xsl:value-of select="quantity" /> </td> 
          <td><xsl:value-of select="price" /></td> 
          <td><xsl:value-of select="price*quantity" /></td> 
         </tr> 
         <tr> 
          <td colspan="3" align="right">Sub-total</td> 
          <td>?how to count subtotal together?</td> 
         </tr> 
        </xsl:for-each> 
        <tr> 
         <td colspan="3" align="right">Grand-total</td> 
         <td>?how to count all subtotal together?</td> 
        </tr> 
       </table> 
      </body> 
     </html> 
    </xsl:template> 
</xsl:stylesheet> 

我的问题是如何列出的国家组中的所有购买日期。这样我就可以算出国家之后的总金额

回答

0

尽管您没有展示您期望看到的内容,但我认为这是一个解决方案,可为您提供所需的解决方案。请注意,不需要<xsl:for-each>;这个基于<xsl:template>的解决方案更具灵活性。

当这个XSLT:

<?xml version="1.0" encoding="UTF-8"?> 
<catalog> 
    <cd PurchaseDate="20000101"> 
    <title>Empire Burlesque</title> 
    <artist>Bob Dylan</artist> 
    <country>USA</country> 
    <quantity>20</quantity> 
    <price>10.90</price> 
    </cd> 
    <cd PurchaseDate="20000101"> 
    <title>Hide your heart</title> 
    <artist>Bonnie Tyler</artist> 
    <country>UK</country> 
    <quantity>10</quantity> 
    <price>9.90</price> 
    </cd> 
    <cd PurchaseDate="20000102"> 
    <title>Greatest Hits</title> 
    <artist>Dolly Parton</artist> 
    <country>USA</country> 
    <quantity>15</quantity> 
    <price>9.90</price> 
    </cd> 
    <cd PurchaseDate="20000101"> 
    <title>Still got the blues</title> 
    <artist>Gary Moore</artist> 
    <country>UK</country> 
    <quantity>5</quantity> 
    <price>10.20</price> 
    </cd> 
    <cd PurchaseDate="20000103"> 
    <title>Eros</title> 
    <artist>Eros Ramazzotti</artist> 
    <country>EU</country> 
    <quantity>6</quantity> 
    <price>9.90</price> 
    </cd> 
    <cd PurchaseDate="20000103"> 
    <title>One night only</title> 
    <artist>Bee Gees</artist> 
    <country>UK</country> 
    <quantity>16</quantity> 
    <price>10.90</price> 
    </cd> 
    <cd PurchaseDate="20000102"> 
    <title>Sylvias Mother</title> 
    <artist>Dr.Hook</artist> 
    <country>UK</country> 
    <quantity>3</quantity> 
    <price>8.10</price> 
    </cd> 
    <cd PurchaseDate="20000101"> 
    <title>Maggie May</title> 
    <artist>Rod Stewart</artist> 
    <country>UK</country> 
    <quantity>8</quantity> 
    <price>8.50</price> 
    </cd> 
    <cd PurchaseDate="20000103"> 
    <title>Romanza</title> 
    <artist>Andrea Bocelli</artist> 
    <country>EU</country> 
    <quantity>30</quantity> 
    <price>10.80</price> 
    </cd> 
</catalog> 

..the产生结果(想)::

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

    <xsl:key name="kCdByCountry" match="cd" use="country"/> 

    <xsl:template match="/*"> 
    <html> 
     <body> 
     <table border="1"> 
      <xsl:apply-templates 
      select="cd[generate-id() =       
         generate-id(key('kCdByCountry', country)[1])]"> 
      <xsl:sort select="country"/> 
      </xsl:apply-templates> 
      <tr bgcolor="#9acd32"> 
      <td colspan="4"> 
       <xsl:text>Total: </xsl:text> 
       <xsl:call-template name="sumProducts"> 
       <xsl:with-param name="pElemList" select="/*/*"/> 
       </xsl:call-template> 
      </td> 
      </tr> 
     </table> 
     </body> 
    </html> 
    </xsl:template> 

    <xsl:template match="cd"> 
    <tr bgcolor="#9acd32"> 
     <td colspan="4"> 
     <xsl:text>Country: </xsl:text> 
     <xsl:value-of select="country"/> 
     </td> 
    </tr> 
    <tr> 
     <td>Purchase Date</td> 
     <td>Quantity</td> 
     <td>Unit Price</td> 
     <td>Total</td> 
    </tr> 
    <xsl:apply-templates select="key('kCdByCountry', country)" mode="values"> 
     <xsl:sort select="@PurchaseDate" data-type="number"/> 
    </xsl:apply-templates> 
    <tr bgcolor="#9acd32"> 
     <td colspan="4"> 
     <xsl:text>Subtotal: </xsl:text> 
     <xsl:call-template name="sumProducts"> 
      <xsl:with-param 
      name="pElemList" 
      select="key('kCdByCountry', country)"/> 
     </xsl:call-template> 
     </td> 
    </tr> 
    </xsl:template> 

    <xsl:template match="cd" mode="values"> 
    <tr> 
     <td> 
     <xsl:value-of select="@PurchaseDate"/> 
     </td> 
     <td> 
     <xsl:value-of select="quantity"/> 
     </td> 
     <td> 
     <xsl:value-of select="price"/> 
     </td> 
     <td> 
     <xsl:value-of select="quantity * price"/> 
     </td> 
    </tr> 
    </xsl:template> 

    <xsl:template name="sumProducts"> 
    <xsl:param name="pElemList"/> 
    <xsl:param name="pTotal" select="0"/> 
    <xsl:choose> 
     <xsl:when test="$pElemList"> 
     <xsl:variable name="vCurrentElem" select="$pElemList[1]"/> 
     <xsl:call-template name="sumProducts"> 
      <xsl:with-param 
      name="pElemList" 
      select="$pElemList[position() &gt; 1]"/> 
      <xsl:with-param 
      name="pTotal" 
      select="$pTotal + $vCurrentElem/price * $vCurrentElem/quantity"/> 
     </xsl:call-template> 
     </xsl:when> 
     <xsl:otherwise> 
     <xsl:value-of select="$pTotal"/> 
     </xsl:otherwise> 
    </xsl:choose> 
    </xsl:template> 
</xsl:stylesheet> 

......是对所提供的XML应用

<html> <body> <table border="1"> <tr bgcolor="#9acd32"> <td colspan="4">Country: EU</td> </tr> <tr> <td>Purchase Date</td> <td>Quantity</td> <td>Unit Price</td> <td>Total</td> </tr> <tr> <td>20000103</td> <td>6</td> <td>9.90</td> <td>59.4</td> </tr> <tr> <td>20000103</td> <td>30</td> <td>10.80</td> <td>324</td> </tr> <tr bgcolor="#9acd32"> <td colspan="4">Subtotal: 383.4</td> </tr> <tr bgcolor="#9acd32"> <td colspan="4">Country: UK</td> </tr> <tr> <td>Purchase Date</td> <td>Quantity</td> <td>Unit Price</td> <td>Total</td> </tr> <tr> <td>20000101</td> <td>10</td> <td>9.90</td> <td>99</td> </tr> <tr> <td>20000101</td> <td>5</td> <td>10.20</td> <td>51</td> </tr> <tr> <td>20000101</td> <td>8</td> <td>8.50</td> <td>68</td> </tr> <tr> <td>20000102</td> <td>3</td> <td>8.10</td> <td>24.3</td> </tr> <tr> <td>20000103</td> <td>16</td> <td>10.90</td> <td>174.4</td> </tr> <tr bgcolor="#9acd32"> <td colspan="4">Subtotal: 416.7</td> </tr> <tr bgcolor="#9acd32"> <td colspan="4">Country: USA</td> </tr> <tr> <td>Purchase Date</td> <td>Quantity</td> <td>Unit Price</td> <td>Total</td> </tr> <tr> <td>20000101</td> <td>20</td> <td>10.90</td> <td>218</td> </tr> <tr> <td>20000102</td> <td>15</td> <td>9.90</td> <td>148.5</td> </tr> <tr bgcolor="#9acd32"> <td colspan="4">Subtotal: 366.5</td> </tr> <tr bgcolor="#9acd32"> <td colspan="4">Total: 1166.6</td> </tr> </table> </body> </html> 

......,当呈现为HTML,看起来像这样:

enter image description here

这种解决方案的秘诀是一个递归命名模板,总结各<quantity><price>组合的产品。该模板用于计算每个国家的小计,最后是所有国家的总计。特别感谢Dimitre Novatchev为此宝石(Multiply 2 numbers and then sum)。

+0

!令人印象深刻!其实我的XML文件有很多CD元素。所以有可能再次在表中对同一日期进行分组? – Chen 2013-04-27 04:49:07

+0

嘿ABach,是什么让你从原始答案中删除了这段文字:“(感谢Dimitre Novatchev提供的很好的拼凑模板):将两个数字相乘,然后与XSLT求和)”。 ? :) – 2013-04-27 04:49:53

+0

哎呀!漫长的一周和深夜;道歉,@DimitreNovatchev!我会把它放回去。 – ABach 2013-04-27 04:52:11

1

这种转变

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:key name="kCDPurchByCountryDate" match="cd" 
    use="concat(@PurchaseDate,'+', country)"/> 

<xsl:template match="/"> 
    <xsl:variable name="vrtfPass1"> 
    <xsl:apply-templates/> 
    </xsl:variable> 

    <xsl:apply-templates select="ext:node-set($vrtfPass1)/*"> 
    <xsl:sort select="@country"/> 
    <xsl:sort select="@PurchaseDate" order="descending"/> 
    </xsl:apply-templates> 
</xsl:template> 

<xsl:template match= 
"cd[generate-id() 
    =generate-id(key('kCDPurchByCountryDate', 
        concat(@PurchaseDate,'+', country) 
        )[1] 
       )]"> 
    <trans country="{country}" PurchaseDate="{@PurchaseDate}"> 
    <amount><xsl:value-of select="quantity*price"/></amount> 
    <xsl:apply-templates mode="group" select= 
    "key('kCDPurchByCountryDate',concat(@PurchaseDate,'+', country)) 
     [position() > 1] 
    "/> 
    </trans> 
</xsl:template> 

<xsl:template match="cd" mode="group"> 
    <amount><xsl:value-of select="quantity*price"/></amount> 
</xsl:template> 
<xsl:template match="text()"/> 

<xsl:template match="trans"> 
    <xsl:copy> 
    <xsl:copy-of select="@*"/> 
    <total><xsl:value-of select="sum(amount)"/></total> 
    </xsl:copy> 
</xsl:template> 
</xsl:stylesheet> 

时所提供的XML文档应用:

<catalog> 
    <cd PurchaseDate="20000101"> 
     <title>Empire Burlesque</title> 
     <artist>Bob Dylan</artist> 
     <country>USA</country> 
     <quantity>20</quantity> 
     <price>10.90</price> 
    </cd> 
    <cd PurchaseDate="20000101"> 
     <title>Hide your heart</title> 
     <artist>Bonnie Tyler</artist> 
     <country>UK</country> 
     <quantity>10</quantity> 
     <price>9.90</price> 
    </cd> 
    <cd PurchaseDate="20000102"> 
     <title>Greatest Hits</title> 
     <artist>Dolly Parton</artist> 
     <country>USA</country> 
     <quantity>15</quantity> 
     <price>9.90</price> 
    </cd> 
    <cd PurchaseDate="20000101"> 
     <title>Still got the blues</title> 
     <artist>Gary Moore</artist> 
     <country>UK</country> 
     <quantity>5</quantity> 
     <price>10.20</price> 
    </cd> 
    <cd PurchaseDate="20000103"> 
     <title>Eros</title> 
     <artist>Eros Ramazzotti</artist> 
     <country>EU</country> 
     <quantity>6</quantity> 
     <price>9.90</price> 
    </cd> 
    <cd PurchaseDate="20000103"> 
     <title>One night only</title> 
     <artist>Bee Gees</artist> 
     <country>UK</country> 
     <quantity>16</quantity> 
     <price>10.90</price> 
    </cd> 
    <cd PurchaseDate="20000102"> 
     <title>Sylvias Mother</title> 
     <artist>Dr.Hook</artist> 
     <country>UK</country> 
     <quantity>3</quantity> 
     <price>8.10</price> 
    </cd> 
    <cd PurchaseDate="20000101"> 
     <title>Maggie May</title> 
     <artist>Rod Stewart</artist> 
     <country>UK</country> 
     <quantity>8</quantity> 
     <price>8.50</price> 
    </cd> 
    <cd PurchaseDate="20000103"> 
     <title>Romanza</title> 
     <artist>Andrea Bocelli</artist> 
     <country>EU</country> 
     <quantity>30</quantity> 
     <price>10.80</price> 
    </cd> 
</catalog> 

产生想要的,正确的结果:

<trans country="EU" PurchaseDate="20000103"> 
    <total>383.4</total> 
</trans> 
<trans country="UK" PurchaseDate="20000103"> 
    <total>174.4</total> 
</trans> 
<trans country="UK" PurchaseDate="20000102"> 
    <total>24.299999999999997</total> 
</trans> 
<trans country="UK" PurchaseDate="20000101"> 
    <total>218</total> 
</trans> 
<trans country="USA" PurchaseDate="20000102"> 
    <total>148.5</total> 
</trans> 
<trans country="USA" PurchaseDate="20000101"> 
    <total>218</total> 
</trans> 

说明

  1. 这是一个非递归两遍转化。对于递归XSLT 1。0解决方案乘号,然后将乘法结果相加的ptoblem的,看到这个问题的答案:Multiply 2 numbers and then sum with XSLT

  2. 的按国家和购买日期第一遍组,使用Muenchian grouping method复合键。

  3. 对于每个组中的多个元素amount产生。

  4. 第二遍浅副本在第一遍中创建的transaction元件。它用一个单一的total元素代替amount儿童。


II。 XSLT 2.0解决方案

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

<xsl:template match="/*"> 
    <xsl:for-each-group select="cd" group-by="concat(country,'+',@PurchaseDate)"> 
    <xsl:sort select="country"/> 
    <xsl:sort select="@PurchaseDate" order="descending"/> 

    <trans country="{country}" PurchaseDate="{@PurchaseDate}"> 
     <total><xsl:sequence select="sum(current-group()/(price*quantity))"/></total> 
    </trans> 
    </xsl:for-each-group> 
</xsl:template> 
</xsl:stylesheet> 
相关问题