如何基于tag=0属性实现表格行数据居中对齐?
XSLT 1.0 实现座位中心对齐表格的解决方案
核心逻辑
XSLT 1.0里的变量是只读不可修改的,而且作用域仅限定义它的上下文,没法像常规编程语言那样在遍历过程中更新变量来统计最大值。所以得先全局计算所有行中tag=0的<seat>元素的前置兄弟数量的最大值,再基于这个值给每行生成左对齐的占位单元格,实现中心对齐效果。
具体实现方案
方案一:用扩展函数(兼容性好,大部分处理器支持)
1. 定义键值对定位每行的tag=0座位
用<xsl:key>快速找到每行里的目标座位,方便后续统计前置兄弟数:
<xsl:key name="target-seat" match="seat[@tag='0']" use="generate-id(..)"/>
2. 计算全局最大前置兄弟数
先把所有行的前置兄弟数收集到变量里,再转成节点集排序取最大值:
<!-- 收集所有行的前置兄弟数量 --> <xsl:variable name="all-left-counts"> <xsl:for-each select="//row[seat[@tag='0']]"> <count><xsl:value-of select="count(key('target-seat', generate-id(.))/preceding-sibling::seat)"/></count> </xsl:for-each> </xsl:variable> <!-- 转成节点集并排序取最大值 --> <xsl:variable name="max-left"> <xsl:for-each select="exsl:node-set($all-left-counts)/count"> <xsl:sort select="." data-type="number" order="descending"/> <xsl:if test="position() = 1"> <xsl:value-of select="."/> </xsl:if> </xsl:for-each> </xsl:variable>
注:exsl:node-set()是多数XSLT处理器(比如Saxon、Xalan)都支持的扩展函数,用来把XSLT1.0里的结果树片段转成可遍历的节点集。
3. 生成对齐的表格行
对每一行,先算当前行tag=0座位的前置兄弟数,再补够和最大值的差值作为左占位单元格,然后输出所有座位:
<table border="1"> <xsl:for-each select="//row"> <tr> <!-- 生成左侧占位空单元格 --> <xsl:variable name="current-target" select="seat[@tag='0']"/> <xsl:variable name="current-left" select="count($current-target/preceding-sibling::seat)"/> <xsl:for-each select="1 to ($max-left - $current-left)"> <td></td> </xsl:for-each> <!-- 输出该行所有座位 --> <xsl:for-each select="seat"> <td><xsl:value-of select="@number"/></td> </xsl:for-each> <!-- 可选:补右侧空单元格让每行宽度一致 --> <xsl:variable name="current-right" select="count($current-target/following-sibling::seat)"/> <!-- 同理计算全局最大后置兄弟数,这里省略重复逻辑 --> <!-- <xsl:for-each select="1 to ($max-right - $current-right)"> <td></td> </xsl:for-each> --> </tr> </xsl:for-each> </table>
方案二:纯XSLT 1.0递归模板(无扩展,兼容性拉满)
如果不能用扩展函数,就写个递归模板遍历所有tag=0的座位,逐个比较找出最大值:
<!-- 递归模板找最大值 --> <xsl:template name="get-max-left"> <xsl:param name="seat-list"/> <xsl:param name="current-max" select="0"/> <xsl:choose> <xsl:when test="$seat-list"> <xsl:variable name="current-count" select="count($seat-list[1]/preceding-sibling::seat)"/> <xsl:call-template name="get-max-left"> <xsl:with-param name="seat-list" select="$seat-list[position() > 1]"/> <xsl:with-param name="current-max" select="if ($current-count > $current-max) then $current-count else $current-max"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:value-of select="$current-max"/> </xsl:otherwise> </xsl:choose> </xsl:template> <!-- 调用模板获取最大值 --> <xsl:variable name="max-left"> <xsl:call-template name="get-max-left"> <xsl:with-param name="seat-list" select="//seat[@tag='0']"/> </xsl:call-template> </xsl:variable>
之后的表格生成逻辑和方案一完全一样,直接用这个$max-left变量就行。
关键注意点
- XSLT 1.0的变量是一次性赋值的,不能中途修改,所以必须先全局算出最大值再用,这是解决你遇到的XPST0008作用域错误的核心
- 如果不需要每行宽度完全一致,右侧的空单元格可以不用补,只处理左侧占位就能实现tag=0座位的中心对齐
- 递归模板是纯标准XSLT语法,适合不能用扩展函数的场景
内容的提问来源于stack exchange,提问作者Grot
相关产品推荐
相关产品推荐

