带空格的XSLT数据透视表

时间:2012-04-04 00:51:30

标签: xml xslt xslt-1.0

所以我有一个xml文档,它不包含最终表中的完整交叉产品,但我需要xslt为我填充空白。如果运行此xslt,您可以看到GCM应该在ABC下。我知道我必须要计算结果,然后添加一个空白但我被卡住了。

<root>
  <Cell>
    <place>BRM</place>
    <test>DMC</test>
    <Score>70</Score>
    <Colour>#008000</Colour>
    <GenerateDate>2012-04-04 12:46:41</GenerateDate>
    <testgroup> Process Plant</testgroup>
  </Cell>
  <Cell>
    <place>GCM</place>
    <test>DMC</test>
    <Score>76</Score>
    <Colour>#008000</Colour>
    <GenerateDate>2012-04-04 12:46:41</GenerateDate>
    <testgroup> Process Plant</testgroup>
  </Cell>
  <Cell>
    <place>GRM</place>
    <test>DMC</test>
    <Score>72</Score>
    <Colour>#008000</Colour>
    <GenerateDate>2012-04-04 12:46:41</GenerateDate>
    <testgroup> Process Plant</testgroup>
  </Cell>
  <Cell>
    <place>NPM</place>
    <test>DMC</test>
    <Score>80</Score>
    <Colour>#008000</Colour>
    <GenerateDate>2012-04-04 12:46:41</GenerateDate>
    <testgroup> Process Plant</testgroup>
  </Cell>
  <Cell>
    <place>PDM</place>
    <test>DMC</test>
    <Score>88</Score>
    <Colour>#008000</Colour>
    <GenerateDate>2012-04-04 12:46:41</GenerateDate>
    <testgroup> Process Plant</testgroup>
  </Cell>
  <Cell>
    <place>PTM</place>
    <test>DMC</test>
    <Score>58</Score>
    <Colour>#FFA100</Colour>
    <GenerateDate>2012-04-04 12:46:41</GenerateDate>
    <testgroup> Process Plant</testgroup>
  </Cell>
  <Cell>
    <place>SRM</place>
    <test>DMC</test>
    <Score>62</Score>
    <Colour>#FFA100</Colour>
    <GenerateDate>2012-04-04 12:46:41</GenerateDate>
    <testgroup> Process Plant</testgroup>
  </Cell>
  <Cell>
    <place>SWC</place>
    <test>DMC</test>
    <Score>85</Score>
    <Colour>#008000</Colour>
    <GenerateDate>2012-04-04 12:46:41</GenerateDate>
    <testgroup> Process Plant</testgroup>
  </Cell>
  <Cell>
    <place>RVS</place>
    <test>DMC</test>
    <Score>84</Score>
    <Colour>#008000</Colour>
    <GenerateDate>2012-04-04 12:46:41</GenerateDate>
    <testgroup> Process Plant</testgroup>
  </Cell>
  <Cell>
    <place>BWM</place>
    <test>SUR</test>
    <Score>66</Score>
    <Colour>#FFA100</Colour>
    <GenerateDate>2012-04-04 12:46:41</GenerateDate>
    <testgroup>Survey</testgroup>
  </Cell>
  <Cell>
    <place>PDM</place>
    <test>SUR</test>
    <Score>85</Score>
    <Colour>#008000</Colour>
    <GenerateDate>2012-04-04 12:46:41</GenerateDate>
    <testgroup>Survey</testgroup>
  </Cell>
  <Cell>
    <place>SRM</place>
    <test>SUR</test>
    <Score>41</Score>
    <Colour>#FFA100</Colour>
    <GenerateDate>2012-04-04 12:46:41</GenerateDate>
    <testgroup>Survey</testgroup>
  </Cell>
</root>

XSLT

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
  <xsl:output method="html" indent="yes"/>

  <xsl:key name="muench" match="/root/Cell/place" use="."/>

  <xsl:key name="test-key" match="/root/Cell/test" use="."/>

  <xsl:template match="/">
    <html>
      <head>
        <title>ABC test Report</title>
        <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
      </head>
      <body >
        <div >
          <header>
            <h2 >
              test group - <xsl:value-of select="/root/Cell/testgroup"/>
            </h2>
          </header>
          <div class="content">
            <table >
              <thead>
                <tr>
                  <th >Place</th>
                  <xsl:for-each select="/root/Cell/test[generate-id() = generate-id(key('test-key',.)[1])]">
                    <th >
                      <xsl:value-of select="."/>
                    </th>
                  </xsl:for-each>
                </tr>
              </thead>
              <tbody>
                <xsl:for-each select="/root/Cell/place[generate-id() = generate-id(key('muench',.)[1])]">
                  <xsl:call-template name="pivot">
                    <xsl:with-param name="place" select="."/>
                  </xsl:call-template>
                </xsl:for-each>
              </tbody>
            </table>
          </div>
          <footer >
            <p></p>
          </footer>
        </div>
      </body>
    </html>
  </xsl:template>

  <xsl:template name="pivot">
    <xsl:param name="place"/>
    <tr>
      <td >
        <xsl:value-of select="$place"/>
      </td>
      <xsl:for-each select="/root/Cell/test[generate-id() = generate-id(key('test-key',.)[1])]">
      <xsl:for-each select="/root/Cell[place=$place and test=.]">
        <xsl:choose>
            <xsl:when test="count(.)=1">
                <td>
                  <xsl:attribute name="style">
                    background-color:<xsl:value-of select="Colour"/>;
                  </xsl:attribute>
                  <xsl:value-of select="Score"/>%
                </td>
            </xsl:when>
            <xsl:otherwise>
                <td>
                </td>
            </xsl:otherwise>
        </xsl:choose>
      </xsl:for-each>
      </xsl:for-each>
    </tr>
  </xsl:template>
</xsl:stylesheet>

输出我想要

<html>
  <table border="1">
    <thead>
      <th>Place</th>
      <th>DMC</th>
      <th>SUR</th>
    </thead>
    <tbody>
      <tr>
        <td>BRM</td>
        <td> 70</td>
        <td> </td>
      </tr>
      <tr>
        <td>BWM</td>
        <td> </td>
        <td> 66</td>
      </tr>
      <tr>
        <td>GCM</td>
        <td> 76</td>
        <td> </td>
      </tr>
      <tr>
        <td>GRM</td>
        <td> 72</td>
        <td> </td>
      </tr>
      <tr>
        <td>NPM</td>
        <td> 80</td>
        <td> </td>
      </tr>
      <tr>
        <td>PDM</td>
        <td> 88</td>
        <td> 85</td>
      </tr>
      <tr>
        <td>PTM</td>
        <td> 58</td>
        <td> </td>
      </tr>
      <tr>
        <td>RVS</td>
        <td> 84</td>
        <td> </td>
      </tr>
      <tr>
        <td>SRM</td>
        <td> 62</td>
        <td> 41</td>
      </tr>
      <tr>
        <td>SWC</td>
        <td> 85</td>
        <td> </td>
      </tr>
    </tbody>
  </table>
</html>

2 个答案:

答案 0 :(得分:1)

这种更短更简单的转化

<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="kTests" match="test" use="."/>
     <xsl:key name="kCellByPlace" match="Cell" use="place"/>

     <xsl:variable name="vTests" select=
      "/*/*/test
             [generate-id()
             =
              generate-id(key('kTests', .)[1])
             ]
      "/>

     <xsl:template match="/*">
      <html>
          <table border="1">
            <thead>
              <th>Place</th>
              <xsl:apply-templates select="$vTests"/>
            </thead>
            <tbody>
              <xsl:apply-templates select=
               "Cell[generate-id() = generate-id(key('kCellByPlace', place))]">
                <xsl:sort select="place"/>
              </xsl:apply-templates>
            </tbody>
          </table>
      </html>
     </xsl:template>

     <xsl:template match="test">
      <th><xsl:value-of select="."/></th>
     </xsl:template>

     <xsl:template match="Cell">
      <tr>
       <td><xsl:value-of select="place"/></td>
        <xsl:apply-templates select="$vTests" mode="row">
         <xsl:with-param name="pCells" select="key('kCellByPlace', place)"/>
        </xsl:apply-templates>
      </tr>
     </xsl:template>

     <xsl:template match="test" mode="row">
      <xsl:param name="pCells"/>

      <td>
        <xsl:value-of select=
         "concat('&#xA0;',$pCells[test=current()]/Score)"/>
      </td>
     </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档

<root>
    <Cell>
        <place>BRM</place>
        <test>DMC</test>
        <Score>70</Score>
        <Colour>#008000</Colour>
        <GenerateDate>2012-04-04 12:46:41</GenerateDate>
        <testgroup> Process Plant</testgroup>
    </Cell>
    <Cell>
        <place>GCM</place>
        <test>DMC</test>
        <Score>76</Score>
        <Colour>#008000</Colour>
        <GenerateDate>2012-04-04 12:46:41</GenerateDate>
        <testgroup> Process Plant</testgroup>
    </Cell>
    <Cell>
        <place>GRM</place>
        <test>DMC</test>
        <Score>72</Score>
        <Colour>#008000</Colour>
        <GenerateDate>2012-04-04 12:46:41</GenerateDate>
        <testgroup> Process Plant</testgroup>
    </Cell>
    <Cell>
        <place>NPM</place>
        <test>DMC</test>
        <Score>80</Score>
        <Colour>#008000</Colour>
        <GenerateDate>2012-04-04 12:46:41</GenerateDate>
        <testgroup> Process Plant</testgroup>
    </Cell>
    <Cell>
        <place>PDM</place>
        <test>DMC</test>
        <Score>88</Score>
        <Colour>#008000</Colour>
        <GenerateDate>2012-04-04 12:46:41</GenerateDate>
        <testgroup> Process Plant</testgroup>
    </Cell>
    <Cell>
        <place>PTM</place>
        <test>DMC</test>
        <Score>58</Score>
        <Colour>#FFA100</Colour>
        <GenerateDate>2012-04-04 12:46:41</GenerateDate>
        <testgroup> Process Plant</testgroup>
    </Cell>
    <Cell>
        <place>SRM</place>
        <test>DMC</test>
        <Score>62</Score>
        <Colour>#FFA100</Colour>
        <GenerateDate>2012-04-04 12:46:41</GenerateDate>
        <testgroup> Process Plant</testgroup>
    </Cell>
    <Cell>
        <place>SWC</place>
        <test>DMC</test>
        <Score>85</Score>
        <Colour>#008000</Colour>
        <GenerateDate>2012-04-04 12:46:41</GenerateDate>
        <testgroup> Process Plant</testgroup>
    </Cell>
    <Cell>
        <place>RVS</place>
        <test>DMC</test>
        <Score>84</Score>
        <Colour>#008000</Colour>
        <GenerateDate>2012-04-04 12:46:41</GenerateDate>
        <testgroup> Process Plant</testgroup>
    </Cell>
    <Cell>
        <place>BWM</place>
        <test>SUR</test>
        <Score>66</Score>
        <Colour>#FFA100</Colour>
        <GenerateDate>2012-04-04 12:46:41</GenerateDate>
        <testgroup>Survey</testgroup>
    </Cell>
    <Cell>
        <place>PDM</place>
        <test>SUR</test>
        <Score>85</Score>
        <Colour>#008000</Colour>
        <GenerateDate>2012-04-04 12:46:41</GenerateDate>
        <testgroup>Survey</testgroup>
    </Cell>
    <Cell>
        <place>SRM</place>
        <test>SUR</test>
        <Score>41</Score>
        <Colour>#FFA100</Colour>
        <GenerateDate>2012-04-04 12:46:41</GenerateDate>
        <testgroup>Survey</testgroup>
    </Cell>
</root>

产生想要的结果

<html>
   <table border="1">
      <thead>
         <th>Place</th>
         <th>DMC</th>
         <th>SUR</th>
      </thead>
      <tbody>
         <tr>
            <td>BRM</td>
            <td>&nbsp;70</td>
            <td>&nbsp;</td>
         </tr>
         <tr>
            <td>BWM</td>
            <td>&nbsp;</td>
            <td>&nbsp;66</td>
         </tr>
         <tr>
            <td>GCM</td>
            <td>&nbsp;76</td>
            <td>&nbsp;</td>
         </tr>
         <tr>
            <td>GRM</td>
            <td>&nbsp;72</td>
            <td>&nbsp;</td>
         </tr>
         <tr>
            <td>NPM</td>
            <td>&nbsp;80</td>
            <td>&nbsp;</td>
         </tr>
         <tr>
            <td>PDM</td>
            <td>&nbsp;88</td>
            <td>&nbsp;85</td>
         </tr>
         <tr>
            <td>PTM</td>
            <td>&nbsp;58</td>
            <td>&nbsp;</td>
         </tr>
         <tr>
            <td>RVS</td>
            <td>&nbsp;84</td>
            <td>&nbsp;</td>
         </tr>
         <tr>
            <td>SRM</td>
            <td>&nbsp;62</td>
            <td>&nbsp;41</td>
         </tr>
         <tr>
            <td>SWC</td>
            <td>&nbsp;85</td>
            <td>&nbsp;</td>
         </tr>
      </tbody>
   </table>
</html>

解释

  1. 我们创建了一个辅助变量$vTests,其中包含test元素的所有不同值。

  2. 每当我们想要生成包含特定地点特定测试分数的tr时,我们会为包含在其中的所有td元素生成“空”test $vTests,其字符串值不等于特定test元素的字符串值,我们生成特定Score元素的test兄弟的字符串值确切地说,此test元素的字符串值等于test中的当前$vTests元素。

答案 1 :(得分:0)

感谢Dimetre的帮助。他展示了如何更有效地使用模板并创建变量。然后我用它来编辑他的脚本来提供我正在寻找的输出。

<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="kTests" match="test" use="."/>

 <xsl:variable name="vTests" select=
  "/*/*/test
         [generate-id()
         =
          generate-id(key('kTests', .)[1])
         ]
  "/>

  <xsl:key name="kPlaces" match="place" use="."/>

 <xsl:variable name="vPlaces" select=
  "/*/*/place
         [generate-id()
         =
          generate-id(key('kPlaces', .)[1])
         ]
  "/>

 <xsl:template match="/*">
  <html>
      <table border="1">
        <thead>
          <th>Place</th>
          <xsl:apply-templates select="$vTests">
           <xsl:sort select="." />
          </xsl:apply-templates>
        </thead>
        <tbody>
          <xsl:apply-templates select="$vPlaces">
           <xsl:sort select="." />
          </xsl:apply-templates>
        </tbody>
      </table>
  </html>
 </xsl:template>

 <xsl:template match="test">
  <th><xsl:value-of select="."/></th>
 </xsl:template>

 <xsl:template match="place">
  <tr>
   <td><xsl:value-of select="."/></td>
    <xsl:apply-templates select="$vTests" mode="row">
      <xsl:sort select="." />
     <xsl:with-param name="pPlace" select="."/>
    </xsl:apply-templates>
  </tr>
 </xsl:template>

 <xsl:template match="test" mode="row">
  <xsl:param name="pPlace"/>
  <td>
    <xsl:value-of select=
     "concat('&#xA0;',/root/Cell[test=current() and place=$pPlace]/Score)"/>
  </td>
 </xsl:template>

</xsl:stylesheet>