2013-04-27 249 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> 
相關問題