是否可以使用xslt设置交叉表视图的样式?

时间:2012-09-12 13:49:51

标签: xml xslt pivot-table crosstab

我有一个看起来像这样的xml文档:

<units>
    <unit>
       <year></year>
       <month></month>
       <qty></qty>
    </unit>
</units>

我想在html中创建此数据的交叉表视图,每行由一年表示,每列由一个月表示,每个值包含特定年/月的数量之和。有点像这样:

      Jan  Feb   Mar   Apr.... etc
2010  345    0    12     0
2011    1   23   344     0
2012   99    1    23     0.... etc

我的主要问题是:xslt甚至可以使用交叉表吗?

我的后续问题是,你可以指出一个xslt新手,比如我自己,正确的方向开始尝试使这项工作吗?

示例数据:

<units>
    <unit>
        <year>2010</year>
        <month>9</month>
        <qty>13320</qty>
    </unit>
    <unit>
        <year>2010</year>
        <month>9</month>
        <qty>2445</qty>
    </unit>
    <unit>
        <year>2010</year>
        <month>10</month>
        <qty>8949</qty>
    </unit>
    <unit>
        <year>2010</year>
        <month>10</month>
        <qty>13650</qty>
    </unit>
    <unit>
        <year>2010</year>
        <month>11</month>
        <qty>4091</qty>
    </unit>
    <unit>
        <year>2010</year>
        <month>11</month>
        <qty>6600</qty>
    </unit>
    <unit>
        <year>2010</year>
        <month>12</month>
        <qty>686</qty>
    </unit>
    <unit>
        <year>2010</year>
        <month>12</month>
        <qty>678</qty>
    </unit>

    <unit>
        <year>2011</year>
        <month>1</month>
        <qty>1234</qty>
    </unit>
    <unit>
        <year>2011</year>
        <month>1</month>
        <qty>12345</qty>
    </unit>
    <unit>
         <year>2011</year>
        <month>2</month>
        <qty>4500</qty>
    </unit>
    <unit>
        <year>2011</year>
        <month>2</month>
        <qty>999</qty>
    </unit>
    <unit>
        <year>2011</year>
        <month>3</month>
        <qty>166</qty>
    </unit>
    <unit>
         <year>2011</year>
        <month>3</month>
        <qty>456666</qty>
    </unit>
    <unit>
        <year>2011</year>
        <month>4</month>
        <qty>41113</qty>
    </unit>
    <unit>
        <year>2011</year>
        <month>4</month>
        <qty>1150</qty>
    </unit>
    <unit>
        <year>2011</year>
        <month>5</month>
        <qty>4150</qty>
    </unit>
    <unit>
        <year>2011</year>
        <month>5</month>
        <qty>491</qty>
    </unit>
    <unit>
        <year>2011</year>
        <month>6</month>
        <qty>11250</qty>
    </unit>
    <unit>
        <year>2011</year>
        <month>6</month>
        <qty>3400</qty>
    </unit>
    <unit>
         <year>2011</year>
        <month>7</month>
        <qty>485</qty>
    </unit>
    <unit>
        <year>2011</year>
        <month>7</month>
        <qty>90</qty>
    </unit>
    <unit>
        <year>2011</year>
        <month>8</month>
        <qty>1606</qty>
    </unit>
    <unit>
         <year>2011</year>
        <month>8</month>
        <qty>202000</qty>
    </unit>
    <unit>
        <year>2011</year>
        <month>9</month>
        <qty>45333</qty>
    </unit>
    <unit>
        <year>2011</year>
        <month>9</month>
        <qty>13650</qty>
    </unit>
    <unit>
        <year>2011</year>
        <month>10</month>
        <qty>4050</qty>
    </unit>
    <unit>
        <year>2011</year>
        <month>10</month>
        <qty>431</qty>
    </unit>
    <unit>
        <year>2011</year>
        <month>11</month>
        <qty>45713</qty>
    </unit>
    <unit>
        <year>2011</year>
        <month>11</month>
        <qty>13690</qty>
    </unit>
    <unit>
        <year>2011</year>
        <month>12</month>
        <qty>4050</qty>
    </unit>
    <unit>
        <year>2011</year>
        <month>12</month>
        <qty>431</qty>
    </unit>

    <unit>
        <year>2012</year>
        <month>1</month>
        <qty>2500</qty>
    </unit>
    <unit>
        <year>2012</year>
        <month>1</month>
        <qty>34100</qty>
    </unit>
    <unit>
        <year>2012</year>
        <month>2</month>
        <qty>400</qty>
    </unit>
    <unit>
        <year>2012</year>
        <month>2</month>
        <qty>99</qty>
    </unit>
    <unit>
        <year>2012</year>
        <month>3</month>
        <qty>1606</qty>
    </unit>
    <unit>
        <year>2012</year>
        <month>3</month>
        <qty>202000</qty>
    </unit>
    <unit>
        <year>2012</year>
        <month>4</month>
        <qty>53773</qty>
    </unit>
    <unit>
        <year>2012</year>
        <month>4</month>
        <qty>13650</qty>
    </unit>
    <unit>
        <year>2012</year>
        <month>5</month>
        <qty>4150</qty>
    </unit>
    <unit>
        <year>2012</year>
        <month>5</month>
        <qty>4231</qty>
    </unit>
    <unit>
        <year>2012</year>
        <month>6</month>
        <qty>278</qty>
    </unit>
    <unit>
        <year>2012</year>
        <month>6</month>
        <qty>6100</qty>
    </unit>
    <unit>
        <year>2012</year>
        <month>7</month>
        <qty>406</qty>
    </unit>
    <unit>
        <year>2012</year>
        <month>7</month>
        <qty>95</qty>
    </unit>

</units>

3 个答案:

答案 0 :(得分:2)

这是一个XSLT 1.0解决方案(可能需要一些工作才能使数字正确对齐):

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:key name="kUnitByY" match="unit" use="year"/>
 <xsl:key name="kUnitByYM" match="unit" use="concat(year,'|',month)"/>

 <xsl:template match="/*">
<xsl:text>      Jan  Feb  Mar  Apr  May  Jun  Jul  Aug  Sep  Oct  Nov  Dec</xsl:text>
  <xsl:apply-templates select=
   "unit[generate-id()=generate-id(key('kUnitByY',year)[1])]">
    <xsl:sort select="year" data-type="number"/>
   </xsl:apply-templates>
 </xsl:template>

 <xsl:template match="unit">
  <xsl:value-of select="concat('&#xA;',year,'  ')"/>

  <xsl:variable name="vCur" select="."/>

  <xsl:for-each select="(//node()|//namespace::*)[not(position() >12)]">
    <xsl:value-of select=
    "sum(key('kUnitByYM', concat($vCur/year,'|',position()))/qty)"/>
    <xsl:text>    </xsl:text>
  </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

在以下XML文档中应用此转换时(没有提供!!!):

            2010        2        3                  2010        3        44                  2010        9        44                  2011        1        五                  2011        3        11                  2011        6        11                  2011        4        15     

产生了想要的正确结果

      Jan  Feb  Mar  Apr  May  Jun  Jul  Aug  Sep  Oct  Nov  Dec
2010  0    3    44    0    0    0    0    0    44    0    0    0    
2011  5    0    11    15    0    11    0    0    0    0    0    0 

答案 1 :(得分:1)

XSLT 1.0解决方案

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:key name="row" match="unit" use="year" />

<xsl:template match="/">
  <xsl:text>     Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec&#x0A;</xsl:text>
  <xsl:apply-templates select="*/unit[
    generate-id() = generate-id( key('row',year)[1])]">
      <xsl:sort select="year" data-type="number" />
  </xsl:apply-templates>    
</xsl:template>

<xsl:template match="unit">
  <xsl:variable name="year" select="year" />
  <xsl:value-of select="concat($year,' ')" />
  <xsl:for-each select="((/)//@*|(/)//node())[position() &lt; 13]">
    <xsl:variable name="month-num" select="position()" />
    <xsl:variable name="sum" select="sum(/*/unit[year=$year][month=$month-num]/qty)" />
    <xsl:value-of select="concat(substring('   ',1,3 - string-length($sum)),$sum,' ')" />
  </xsl:for-each>  
  <xsl:value-of select="'&#x0A;'" />
</xsl:template>

</xsl:stylesheet>

...会接受这样的输入......

<units>
    <unit>
       <year>2010</year>
       <month>2</month>
       <qty>3</qty>
    </unit>
    <unit>
       <year>2010</year>
       <month>3</month>
       <qty>44</qty>
    </unit>
    <unit>
       <year>2011</year>
       <month>1</month>
       <qty>5</qty>
    </unit>
    <unit>
       <year>2011</year>
       <month>3</month>
       <qty>11</qty>
    </unit>
    <unit>
       <year>2011</year>
       <month>4</month>
       <qty>15</qty>
    </unit>
</units>

...并生成这样的文字......

     Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
2010   0   3  44   0   0   0   0   0   0   0   0   0 
2011   5   0  11  15   0   0   0   0   0   0   0   0 

XSLT 2.0解决方案

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>

<xsl:template match="/">
       Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
  <xsl:for-each-group select="*/unit" group-by="year">
    <xsl:sort select="year" data-type="number" />
    <xsl:value-of select="concat(current-grouping-key(),' ')" />  
      <xsl:value-of select="        
          (string-join(
          for $month-num in 1 to 12 return
                for $sum in sum(current-group()/qty) return
                  concat(substring('   ',1,3 - string-length($sum)),$sum),
          ' '), '&#x0A;')" />
 </xsl:for-each-group>    
</xsl:template>

</xsl:stylesheet>

更新1

Dimitre建议添加线路终端校正。


更新2

删除输出中的前导零,但保留列对齐。


注意事项

  1. XSLT 1.0解决方案仅在最大总和小于1000时才有效。如果没有,则进行相应调整。
  2. Dimitre利用关键而不是重新计算'/ * / unit [year = $ year] [month = $ month-num]'的解决方案是优越的。也许最佳解决方案是使用他的key()样式解决方案来计算总和,但我的代码片段用于非前导零列对齐。

答案 2 :(得分:0)

您可以使用Muenchian Method

执行此操作