请为Table rowspan和colspan问题建议XSLT代码

时间:2014-02-06 16:45:06

标签: xslt

<article>

<table id="tbl1">
<caption><p>Table 1. Sample Table</p></caption>

<thead>
<tr>
    <td colspan="3">I</td>
    <td colspan="4">II</td>
</tr>

<tr>
    <td>Sl. No.</td>
    <td>Name</td>
    <td>Place</td>
    <td>Subject 1</td>
    <td>Subject 2</td>
    <td>Subject 3</td>
    <td>Grade</td>
</tr>
</thead>

<tbody>
<tr>
    <td rowspan="3">1</td>
    <td colspan="2">Kishan</td>
    <td>95</td>
    <td>96</td>
    <td rowspan="2">97</td>
    <td>A</td>
</tr>

<tr>

    <td>Kishan</td>
    <td>Bangalore</td>
    <td>94</td>
    <td>96</td>

    <td>A</td>
</tr>

<tr>

    <td>Likhith</td>
    <td>Bhadravathi</td>
    <td>94</td>
    <td>94</td>
    <td>99</td>
    <td>A</td>
</tr>
</tbody>
</table>

</article>

必需OutPut:如果colspan是2在第二个单元格中编码,则第三个不应该在那里,下一个单元格名称应为“colname =”3“(起始索引为0)。对于rowspan,如果存在行的第一个单元格则相同如果rowspan =“3”,则接下来的两行不应该具有colname =“0”,接下来的两行起始单元格将具有名称=“1”(起始索引为0,这就是为什么1表示第二个单元格)。请建议对于XSLT编码,两个地址同时存在于同一个表中的rowspan和colspan。

    <article>

<table id="tbl1">
<caption><p>Table 1. Sample Table</p></caption>

<thead>
<tr>
    <td colname="0:0">I</td>
    <td colname="0:3">II</td>
</tr>

<tr>
    <td colname="1:0">Sl. No.</td>
    <td colname="1:1">Name</td>
    <td colname="1:2">Place</td>
    <td colname="1:3">Subject 1</td>
    <td colname="1:4">Subject 2</td>
    <td colname="1:5">Subject 3</td>
    <td colname="1:6">Grade</td>
</tr>
</thead>


<tbody>
<tr>
    <td colname="2:0">1</td>
    <td colname="2:1">Kishan</td>
    <td colname="2:3">95</td>
    <td colname="2:4">96</td>
    <td colname="2:5">97</td>
    <td colname="2:6">A</td>
</tr>

<tr>

    <td colname="3:1">Kishan</td>
    <td colname="3:2">Bangalore</td>
    <td colname="3:3">94</td>
    <td colname="3:4">96</td>

    <td colname="3:6">A</td>
</tr>

<tr>

    <td colname="4:1">Likhith</td>
    <td colname="4:2">Bhadravathi</td>
    <td colname="4:3">94</td>
    <td colname="4:4">94</td>
    <td colname="4:5">99</td>
    <td colname="4:6">A</td>
</tr>
</tbody>
</table>

</article>

StackOverFlow站点的XSLT代码:

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

<!--rowspan in table with xslt-->
<xsl:template match="TABLE2">
  <tbody>
    <xsl:call-template name="processRows">
      <xsl:with-param name="rows" select="ROW"/>
    </xsl:call-template>
  </tbody>
</xsl:template>

<xsl:template name="processRows">
  <xsl:param name="rows"/>
  <xsl:param name="index" select="1"/>
  <!-- Bit vector for the columns -->
  <xsl:param name="col1" select="0"/>
  <xsl:param name="col2" select="0"/>
  <xsl:param name="col3" select="0"/>
  <xsl:param name="col4" select="0"/>
  <xsl:param name="col5" select="0"/>
  <xsl:param name="col6" select="0"/>

  <xsl:variable name="cellsBefore2">
    <xsl:choose>
      <xsl:when test="$col1 > 0">0</xsl:when>
      <xsl:otherwise>1</xsl:otherwise>
    </xsl:choose>
  </xsl:variable>
  <xsl:variable name="cellsBefore3">
    <xsl:choose>
      <xsl:when test="$col2 > 0">
        <xsl:value-of select="$cellsBefore2"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$cellsBefore2 + 1"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:variable>

   <xsl:variable name="cellsBefore4">
    <xsl:choose>
       <xsl:when test="$col3 > 0">
        <xsl:value-of select="$cellsBefore3"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$cellsBefore3 + 1"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:variable>

   <xsl:variable name="cellsBefore5">
    <xsl:choose>
       <xsl:when test="$col4 > 0">
        <xsl:value-of select="$cellsBefore4"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$cellsBefore4 + 1"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:variable>

  <xsl:variable name="cellsBefore6">
    <xsl:choose>
       <xsl:when test="$col5 > 0">
        <xsl:value-of select="$cellsBefore5"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$cellsBefore5 + 1"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:variable>



  <row>
    <xsl:if test="$col1 = 0">
      <entry colname="1">
        <xsl:value-of select="$rows[$index]/CELL[1]/text()"/>
      </entry>
    </xsl:if>
    <xsl:if test="$col2 = 0">
      <entry colname="2">
        <xsl:value-of select="$rows[$index]/CELL[$cellsBefore2 + 1]/text()"/>
      </entry>
    </xsl:if>
    <xsl:if test="$col3 = 0">
      <entry colname="3">
        <xsl:value-of select="$rows[$index]/CELL[$cellsBefore3 + 1]/text()"/>
      </entry>
    </xsl:if>
    <xsl:if test="$col4 = 0">
      <entry colname="4">
        <xsl:value-of select="$rows[$index]/CELL[$cellsBefore4 + 1]/text()"/>
      </entry>
    </xsl:if>
     <xsl:if test="$col5 = 0">
      <entry colname="5">
        <xsl:value-of select="$rows[$index]/CELL[$cellsBefore5 + 1]/text()"/>
      </entry>
    </xsl:if>
     <xsl:if test="$col6 = 0">
      <entry colname="6">
        <xsl:value-of select="$rows[$index]/CELL[$cellsBefore6 + 1]/text()"/>
      </entry>
    </xsl:if>


  </row>
  <xsl:if test="$index &lt; count($rows)">
    <xsl:call-template name="processRows">
      <xsl:with-param name="rows" select="$rows"/>
      <xsl:with-param name="index" select="$index + 1"/>
      <xsl:with-param name="col1">
        <xsl:choose>
          <xsl:when test="$col1 > 0">
            <xsl:value-of select="$col1 - 1"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="number($rows[$index]/CELL[1]/@ROWSPAN) - 1"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:with-param>
      <xsl:with-param name="col2">
        <xsl:choose>
          <xsl:when test="$col2 > 0">
            <xsl:value-of select="$col2 - 1"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="number($rows[$index]/CELL[$cellsBefore2 + 1]/@ROWSPAN) - 1"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:with-param>
      <xsl:with-param name="col3">
        <xsl:choose>
          <xsl:when test="$col3 > 0">
            <xsl:value-of select="$col3 - 1"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="number($rows[$index]/CELL[$cellsBefore3 + 1]/@ROWSPAN) - 1"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:with-param>
      <xsl:with-param name="col4">
        <xsl:choose>
          <xsl:when test="$col4 > 0">
            <xsl:value-of select="$col4 - 1"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="number($rows[$index]/CELL[$cellsBefore4 + 1]/@ROWSPAN) - 1"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:with-param>
      <xsl:with-param name="col5">
        <xsl:choose>
          <xsl:when test="$col5 > 0">
            <xsl:value-of select="$col5 - 1"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="number($rows[$index]/CELL[$cellsBefore5 + 1]/@ROWSPAN) - 1"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:with-param>
       <xsl:with-param name="col6">
        <xsl:choose>
          <xsl:when test="$col6 > 0">
            <xsl:value-of select="$col6 - 1"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="number($rows[$index]/CELL[$cellsBefore6 + 1]/@ROWSPAN) - 1"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:with-param>


    </xsl:call-template>
  </xsl:if>
</xsl:template>
</xsl:stylesheet> 

1 个答案:

答案 0 :(得分:6)

这一点都不简单。基本上,您正在询问如何通过将每个单元格定位在行等和列的(等间距)x-y网格上来呈现HTML表格直观

这很复杂,因为每个单元格的位置不仅取决于同一行中前面单元格的宽度(colspan),还取决于前面行中跨越的单元格的位置不止一排。在处理前面的单元格之前,这个位置是未知的 - 所以这是一个巨大的渲染即用级联操作。

由于这种复杂性,我建议在引入其他约束之前首先单独解决基本问题(例如,单独的标题行或从0开始的数字)。

为了测试,我使用下表 1 作为输入

<table border="1">
    <tr>
        <td>Column 1</td>
        <td>Column 2</td>
        <td>Column 3</td>
    </tr>
    <tr>
        <td rowspan="2">A</td>
        <td colspan="2">B</td>
    </tr>
    <tr>
        <td>C</td>
        <td>D</td>
    </tr>
    <tr>
        <td>E</td>
        <td rowspan="2" colspan="2">F</td>
    </tr>
    <tr>
        <td>G</td>
    </tr>
    <tr>
        <td colspan="3">H</td>
    </tr>
</table>

应用以下样式表:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:template match="/table">
    <table>
        <xsl:text>&#10;</xsl:text>
        <xsl:call-template name="generate-rows">
            <xsl:with-param name="current-row" select="1"/>
            <xsl:with-param name="last-row" select="count(tr)"/>
        </xsl:call-template>
    </table>
</xsl:template>


<xsl:template name="generate-rows">
    <xsl:param name="current-row"/>
    <xsl:param name="last-row"/>
    <xsl:param name="result" select="some-dummy-node-to-make-this-a-node"/>

    <!-- append current-row to previous result -->
    <xsl:variable name="new-result">
        <xsl:copy-of select="$result"/>
        <row num="{$current-row}">
            <xsl:text>&#10;</xsl:text>
            <!-- generate cells for current-row -->
            <xsl:call-template name="generate-cells">
                <xsl:with-param name="current-row" select="$current-row"/>
                <xsl:with-param name="current-cell" select="1"/>
                <xsl:with-param name="x" select="1"/>
                <xsl:with-param name="last-cell" select="count(tr[$current-row]/td)"/>
                <xsl:with-param name="previous-rows" select="$result"/>
            </xsl:call-template>
        </row>
        <xsl:text>&#10;</xsl:text>
    </xsl:variable>

    <xsl:choose>
        <xsl:when test="$current-row &lt; $last-row">
            <!-- recursive call -->
            <xsl:call-template name="generate-rows">
                <xsl:with-param name="current-row" select="$current-row + 1"/>
                <xsl:with-param name="last-row" select="$last-row"/>
                <xsl:with-param name="result" select="$new-result"/>
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <!-- return result -->
            <xsl:copy-of select="$new-result"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>


<xsl:template name="generate-cells">
    <xsl:param name="current-row"/>
    <xsl:param name="current-cell"/>
    <xsl:param name="x"/>
    <xsl:param name="last-cell"/>
    <xsl:param name="previous-rows"/>

    <xsl:variable name="my-cell" select="tr[$current-row]/td[$current-cell]" />

    <xsl:choose>
        <!-- if there's a collision, move one place to the right -->
        <xsl:when test="exsl:node-set($previous-rows)/row/cell[@x &lt;= $x and @x + @width > $x and @y + @height > $current-row]">
            <xsl:call-template name="generate-cells">
                <xsl:with-param name="current-row" select="$current-row"/>
                <xsl:with-param name="current-cell" select="$current-cell"/>
                <xsl:with-param name="x" select="$x + 1"/>
                <xsl:with-param name="last-cell" select="$last-cell"/>
                <xsl:with-param name="previous-rows" select="$previous-rows"/>
            </xsl:call-template>
        </xsl:when>

        <xsl:otherwise>     
            <xsl:variable name="width">
                <xsl:choose>
                    <xsl:when test="$my-cell/@colspan">
                        <xsl:value-of select="$my-cell/@colspan"/>
                    </xsl:when>
                    <xsl:otherwise>1</xsl:otherwise>
                </xsl:choose>
            </xsl:variable>

             <xsl:variable name="height">
                <xsl:choose>
                    <xsl:when test="$my-cell/@rowspan">
                        <xsl:value-of select="$my-cell/@rowspan"/>
                    </xsl:when>
                    <xsl:otherwise>1</xsl:otherwise>
                </xsl:choose>
             </xsl:variable>

            <xsl:text>&#9;</xsl:text>
             <cell num="{$current-cell}" y="{$current-row}" x="{$x}" width="{$width}" height="{$height}">
                 <xsl:value-of select="$my-cell"/>
             </cell>
            <xsl:text>&#10;</xsl:text>

            <xsl:if test="$current-cell &lt; $last-cell">
                <xsl:call-template name="generate-cells">
                    <xsl:with-param name="current-row" select="$current-row"/>
                    <xsl:with-param name="current-cell" select="$current-cell + 1"/>
                    <xsl:with-param name="x" select="$x + $width"/>
                    <xsl:with-param name="last-cell" select="count(tr[$current-row]/td)"/>
                    <xsl:with-param name="previous-rows" select="$previous-rows"/>
                </xsl:call-template>
            </xsl:if>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

</xsl:stylesheet>

生成以下结果

<?xml version="1.0" encoding="UTF-8"?>
<table>
<row num="1">
    <cell num="1" y="1" x="1" width="1" height="1">Column 1</cell>
    <cell num="2" y="1" x="2" width="1" height="1">Column 2</cell>
    <cell num="3" y="1" x="3" width="1" height="1">Column 3</cell>
</row>
<row num="2">
    <cell num="1" y="2" x="1" width="1" height="2">A</cell>
    <cell num="2" y="2" x="2" width="2" height="1">B</cell>
</row>
<row num="3">
    <cell num="1" y="3" x="2" width="1" height="1">C</cell>
    <cell num="2" y="3" x="3" width="1" height="1">D</cell>
</row>
<row num="4">
    <cell num="1" y="4" x="1" width="1" height="1">E</cell>
    <cell num="2" y="4" x="2" width="2" height="2">F</cell>
</row>
<row num="5">
    <cell num="1" y="5" x="1" width="1" height="1">G</cell>
</row>
<row num="6">
    <cell num="1" y="6" x="1" width="3" height="1">H</cell>
</row>
</table>

如您所见,每个单元格的x-y定位对应于浏览器中原始表格的可视化渲染:

enter image description here

-
1.来自http://en.wikipedia.org/wiki/Help:Table


对于 XSLT 2.0

将样式表声明更改为:

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

将第66行更改为:

<xsl:when test="$previous-rows/row/cell[@x &lt;= $x and @x + @width > $x and @y + @height > $current-row]">
相关问题