如何用XSLT为XML表格rowspan对应的行添加<testentry/>元素?
修正XML表格rowspan对应位置插入的XSLT代码
需求回顾
当XML表格中的<td>元素带有rowspan属性时,需要在该单元格跨越的后续每一行的对应列位置插入<testentry/>空元素。原代码错误地在所有行插入元素,需修正逻辑实现精准插入。
示例输入XML
<table> <tr> <td rowspan="3">跨3行的单元格</td> <td>普通单元格1</td> </tr> <tr> <td>普通单元格2</td> </tr> <tr> <td>普通单元格3</td> </tr> <tr> <td>普通单元格4</td> <td rowspan="2">跨2行的单元格</td> </tr> <tr> <td>普通单元格5</td> </tr> </table>
预期输出XML
<table> <tr> <td rowspan="3">跨3行的单元格</td> <td>普通单元格1</td> </tr> <tr> <testentry/> <td>普通单元格2</td> </tr> <tr> <testentry/> <td>普通单元格3</td> </tr> <tr> <td>普通单元格4</td> <td rowspan="2">跨2行的单元格</td> </tr> <tr> <td>普通单元格5</td> <testentry/> </tr> </table>
修正后的XSLT代码(XSLT 1.0兼容)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <!-- 处理表格,启动第一行的处理,初始无待处理rowspan --> <xsl:template match="table"> <table> <xsl:if test="tr[1]"> <xsl:apply-templates select="tr[1]"> <xsl:with-param name="pending-rowspans" select="''"/> </xsl:apply-templates> </xsl:if> </table> </xsl:template> <!-- 处理单行,接收当前待处理的rowspan列表 --> <xsl:template match="tr"> <xsl:param name="pending-rowspans"/> <tr> <!-- 1. 处理待处理rowspan:插入testentry并更新计数 --> <xsl:variable name="updated-pending"> <xsl:for-each select="$pending-rowspans/span"> <testentry/> <!-- 剩余次数>1时,保留到下一行的待处理列表 --> <xsl:if test=". > 1"> <span><xsl:value-of select=". - 1"/></span> </xsl:if> </xsl:for-each> </xsl:variable> <!-- 2. 输出当前行的所有td元素 --> <xsl:apply-templates select="td"/> </tr> <!-- 准备下一行的待处理rowspan:更新后的旧记录 + 当前行新的rowspan(值>1的) --> <xsl:variable name="new-pending"> <!-- 保留更新后仍需继续的rowspan --> <xsl:copy-of select="$updated-pending/span"/> <!-- 添加当前行中rowspan>1的td,计数为rowspan值-1 --> <xsl:for-each select="td[@rowspan and number(@rowspan) > 1]"> <span><xsl:value-of select="number(@rowspan) - 1"/></span> </xsl:for-each> </xsl:variable> <!-- 递归处理下一行 --> <xsl:if test="following-sibling::tr[1]"> <xsl:apply-templates select="following-sibling::tr[1]"> <xsl:with-param name="pending-rowspans" select="$new-pending"/> </xsl:apply-templates> </xsl:if> </xsl:template> <!-- 复制td元素及其属性、内容 --> <xsl:template match="td"> <xsl:copy> <xsl:copy-of select="@*"/> <xsl:copy-of select="node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
代码逻辑说明
- 跟踪待处理rowspan:通过
pending-rowspans参数维护一个列表,记录每个列还需要插入<testentry/>的次数。 - 逐行处理:
- 先遍历待处理列表,对应列插入
<testentry/>,并将计数减1,计数为0的不再保留。 - 输出当前行的所有
<td>元素。
- 先遍历待处理列表,对应列插入
- 更新待处理列表:收集当前行中
rowspan>1的<td>,将其rowspan值减1后加入下一行的待处理列表。 - 递归处理后续行:将更新后的待处理列表传递给下一行,重复上述流程。
这种方式能精准定位需要插入<testentry/>的列,避免无差别插入元素的问题。
内容的提问来源于stack exchange,提问作者ssr1012
相关产品推荐
相关产品推荐

