You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

带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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 05:37:02