【问题标题】:How to group parent attribute by using Muenchian Method?如何使用 Muenchian 方法对父属性进行分组?
【发布时间】:2013-04-21 06:25:41
【问题描述】:

我是 XSLT 的初学者,对 Muenchian 分组方法感到困惑。 这是我的 XML 文档

<?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>

我的问题是如何列出国家/地区组中的所有购买日期。这样我就可以统计跟随国家的总金额了

【问题讨论】:

    标签: xml xslt muenchian-grouping


    【解决方案1】:

    虽然您没有展示您希望看到的内容,但我认为这里有一个解决方案,可以满足您的需求。请注意,不需要&lt;xsl:for-each&gt;;这个基于&lt;xsl:template&gt; 的解决方案更加灵活。

    当这个 XSLT:

    <?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 应用:

    <?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>
    

    ..产生(想要的?)结果:

    <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 时,如下所示:

    这个解决方案的秘诀是一个递归命名模板,它将每个&lt;quantity&gt; 和&lt;price&gt; 组合的乘积相加。此模板用于计算每个国家/地区的小计,最后计算所有国家/地区的总数。特别感谢 Dimitre Novatchev 提供此 gem (Multiply 2 numbers and then sum)。

    【讨论】:

    • !这令人印象深刻!实际上我的 xml 文件有很多 cd 元素。所以有可能在表中再次分组相同的日期?
    • 嘿,ABach,是什么让您从原始答案中删除了此文本:“(感谢 Dimitre Novatchev 提供了精美的组合模板):将 2 个数字相乘,然后与 XSLT 相加)。” ? :)
    • 哎呀!漫长的一周和一个深夜;道歉,@DimitreNovatchev!我会把它放回去。
    • @Chen - 我不确定你的意思。您能否使用所需的 XML 输出更新您的问题?
    【解决方案2】:

    这种转变:

    <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 解决方案,请参阅此问题的答案:Multiply 2 numbers and then sum with XSLT:

    2. 使用 Muenchian grouping method 和复合键按国家和购买日期分组。

    3. 为每个组生成多个amount 元素。

    4. 第二遍浅拷贝在第一遍中创建的transaction 元素。它将amount 子元素替换为单个total 元素。


    二。 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>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-07-30
      • 2014-08-07
      • 1970-01-01
      • 1970-01-01
      • 2017-11-13
      • 2017-11-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多