1

我是 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>

我的问题是如何列出国家组中的所有购买日期。这样我就可以算出跟随国家的总量了

4

2 回答 2

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 解决方案,请参阅此问题的答案:乘以 2 个数字,然后与 XSLT 求和

  2. 第一遍按国家和购买日期分组,使用带有复合键的Muenchian 分组方法。

  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>
于 2013-04-27T03:56:17.320 回答
0

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

当这个 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 时,它看起来像这样:

在此处输入图像描述

这个解决方案的秘诀是一个递归命名模板,它对每个<quantity><price>组合的乘积求和。此模板用于计算每个国家/地区的小计,最后计算所有国家/地区的总数。特别感谢 Dimitre Novatchev 提供此宝石(乘以 2 个数字,然后求和)。

于 2013-04-27T03:39:09.013 回答