2

我有一个看起来像这样的 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>
4

3 回答 3

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 5 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 
于 2012-09-13T04:19:13.200 回答
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() 风格的解决方案来计算总和,但我的代码片段用于非前导零列对齐。
于 2012-09-12T16:03:56.113 回答
0

您可以使用Muenchian Method

于 2012-09-12T15:23:38.193 回答