带rowspan的XHTML表格转DITA规范表格的XSLT实现问题
XHTML带rowspan表格转DITA表格的XSLT解决方案
核心需求:将XHTML中带rowspan属性的<td>转换为DITA表格中带morerows属性的<entry>,同时自动处理后续行中被跨行占用的单元格(DITA不需要在后续行重复写这些单元格)。
关键逻辑说明
- DITA的
morerows属性值 = XHTML的rowspan值 - 1(比如XHTMLrowspan="3"对应DITAmorerows="2") - 需要跟踪当前表格中各列的跨行剩余行数,在遍历后续行时跳过已被跨行占用的单元格位置
完整XSLT代码
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 匹配XHTML表格,转换为DITA表格 --> <xsl:template match="table"> <table> <xsl:apply-templates select="thead | tbody"/> </table> </xsl:template> <!-- 匹配表头行,转换为DITA表头行 --> <xsl:template match="thead/tr"> <row> <xsl:apply-templates select="th"/> </row> </xsl:template> <!-- 匹配表头单元格,转换为DITA表头entry --> <xsl:template match="th"> <entry> <xsl:apply-templates/> </entry> </xsl:template> <!-- 初始化跨行跟踪变量,处理表格体的行 --> <xsl:template match="tbody"> <xsl:variable name="colCount" select="count(tr[1]/td)"/> <!-- 初始化剩余跨行数组,初始值全为0 --> <xsl:call-template name="processRows"> <xsl:with-param name="rows" select="tr"/> <xsl:with-param name="remainingSpans" select="0"/> <xsl:with-param name="colCount" select="$colCount"/> </xsl:call-template> </xsl:template> <!-- 递归处理每一行 --> <xsl:template name="processRows"> <xsl:param name="rows"/> <xsl:param name="remainingSpans"/> <xsl:param name="colCount"/> <xsl:if test="$rows"> <row> <!-- 处理当前行的单元格,结合剩余跨行信息 --> <xsl:call-template name="processCells"> <xsl:with-param name="cells" select="$rows[1]/td"/> <xsl:with-param name="remainingSpans" select="$remainingSpans"/> <xsl:with-param name="colIndex" select="1"/> </xsl:call-template> </row> <!-- 更新剩余跨行数组:所有值减1,小于0的设为0 --> <xsl:variable name="updatedSpans"> <xsl:for-each select="$remainingSpans/*"> <span><xsl:value-of select="max(0, . - 1)"/></span> </xsl:for-each> </xsl:variable> <!-- 递归处理下一行 --> <xsl:call-template name="processRows"> <xsl:with-param name="rows" select="$rows[position() > 1]"/> <xsl:with-param name="remainingSpans" select="$updatedSpans"/> <xsl:with-param name="colCount" select="$colCount"/> </xsl:call-template> </xsl:if> </xsl:template> <!-- 处理当前行的每个单元格 --> <xsl:template name="processCells"> <xsl:param name="cells"/> <xsl:param name="remainingSpans"/> <xsl:param name="colIndex"/> <xsl:choose> <!-- 如果当前列还有剩余跨行,跳过输出单元格 --> <xsl:when test="$remainingSpans/span[$colIndex] > 0"> <xsl:call-template name="processCells"> <xsl:with-param name="cells" select="$cells"/> <xsl:with-param name="remainingSpans" select="$remainingSpans"/> <xsl:with-param name="colIndex" select="$colIndex + 1"/> </xsl:call-template> </xsl:when> <!-- 处理当前单元格 --> <xsl:when test="$cells"> <entry> <!-- 处理rowspan:转换为morerows(值为rowspan-1) --> <xsl:if test="$cells[1]/@rowspan and number($cells[1]/@rowspan) > 1"> <xsl:attribute name="morerows"> <xsl:value-of select="number($cells[1]/@rowspan) - 1"/> </xsl:attribute> </xsl:if> <xsl:apply-templates select="$cells[1]/node()"/> </entry> <!-- 更新剩余跨行数组:当前列设为rowspan-1(如果有),否则保持0 --> <xsl:variable name="newSpans"> <xsl:for-each select="$remainingSpans/span"> <xsl:variable name="currentPos" select="position()"/> <span> <xsl:choose> <xsl:when test="$currentPos = $colIndex and $cells[1]/@rowspan"> <xsl:value-of select="number($cells[1]/@rowspan) - 1"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="."/> </xsl:otherwise> </xsl:choose> </span> </xsl:for-each> </xsl:variable> <!-- 处理下一个单元格 --> <xsl:call-template name="processCells"> <xsl:with-param name="cells" select="$cells[position() > 1]"/> <xsl:with-param name="remainingSpans" select="$newSpans"/> <xsl:with-param name="colIndex" select="$colIndex + 1"/> </xsl:call-template> </xsl:when> </xsl:choose> </xsl:template> <!-- 匹配文本节点,直接输出 --> <xsl:template match="text()"> <xsl:value-of select="."/> </xsl:template> </xsl:stylesheet>
示例验证
原XHTML表格
<table> <tbody> <tr> <td rowspan="3">跨行3行的单元格</td> <td>普通单元格1</td> <td>普通单元格2</td> </tr> <tr> <td>普通单元格3</td> <td>普通单元格4</td> </tr> <tr> <td>普通单元格5</td> <td>普通单元格6</td> </tr> </tbody> </table>
转换后的DITA表格
<table> <row> <entry morerows="2">跨行3行的单元格</entry> <entry>普通单元格1</entry> <entry>普通单元格2</entry> </row> <row> <entry>普通单元格3</entry> <entry>普通单元格4</entry> </row> <row> <entry>普通单元格5</entry> <entry>普通单元格6</entry> </row> </table>
注意事项
- 该方案假设XHTML表格的列数是固定的(第一行的单元格数为总列数)
- 若表格包含混合
rowspan和colspan,需要额外扩展colspan的处理逻辑(DITA用cols属性对应XHTML的colspan)
内容的提问来源于stack exchange,提问作者ak5555
相关产品推荐
相关产品推荐

