如何在XSLT 1.0的for-each循环中按条件计数并限制输出
问题
在XSLT 1.0环境下,需要在for-each循环中按条件显式计数,position()函数无法满足当前场景需求。现有输入XML、XSLT代码如下:
输入XML
<em> <doc> <info> <str>/abc/sdf</str> <str>/def/gjh</str> <str>/ghi/jhk</str> <str>/klm/jhhj</str> <str>/abc/hafghi</str> <str>/ghi/tyuxd</str> <str>/abc/ert</str> <str>/def/kjldg</str> <str>/abc/ghk</str> <str>/pqr/wsej</str> <str>/ghi/sdf</str> <str>/ghi/fgh</str> <str>/ghi/sfd</str> <str>/ghi/hgjgh</str> <str>/ghi/hfkkd</str> </info> </doc> </em>
现有XSLT代码
<req> <xsl:for-each select="/em/doc/info/str"> <xsl:variable name="pos" select="position()"/> <xsl:if test="/em/doc/info/str[$pos] != '' and starts-with(/em/doc/info/str[$pos],'/abc/')"> <input> <inf> <xsl:valus-of select="/em/doc/info/str[$pos]"/> </inf> </input> </xsl:if> </xsl:for-each> <xsl:for-each select="/em/doc/info/str"> <xsl:variable name="pos" select="position()"/> <xsl:if test="/em/doc/info/str[$pos] != '' and starts-with(/em/doc/info/str[$pos],'/ghi/')"> <input> <inf> <xsl:valus-of select="/em/doc/info/str[$pos]"/> </inf> </input> </xsl:if> </xsl:for-each> </req>
需求
- 仅保留前2个以
/abc/开头的<str>元素,生成<input>/<inf>节点; - 仅保留前6个以
/ghi/开头的<str>元素,生成<nxtinput>/<inf>节点;
期望输出
<req> <input> <inf>/abc/sdf</inf> </input> <input> <inf>/abc/hafghi</inf> </input> <nxtinput> <inf>/ghi/jhk</inf> </nxtinput> <nxtinput> <inf>/ghi/tyuxd</inf> </nxtinput> <nxtinput> <inf>/ghi/sdf</inf> </nxtinput> <nxtinput> <inf>/ghi/fgh</inf> </nxtinput> <nxtinput> <inf>/ghi/sfd</inf> </nxtinput> <nxtinput> <inf>/ghi/hgjgh</inf> </nxtinput> </req>
修改后的XSLT代码
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <xsl:template match="/"> <req> <!-- 处理前2个/abc/开头的str节点 --> <xsl:for-each select="/em/doc/info/str[starts-with(., '/abc/')]"> <xsl:if test="position() <= 2"> <input> <inf> <xsl:value-of select="."/> </inf> </input> </xsl:if> </xsl:for-each> <!-- 处理前6个/ghi/开头的str节点 --> <xsl:for-each select="/em/doc/info/str[starts-with(., '/ghi/')]"> <xsl:if test="position() <= 6"> <nxtinput> <inf> <xsl:value-of select="."/> </inf> </nxtinput> </xsl:if> </xsl:for-each> </req> </xsl:template> </xsl:stylesheet>
关键修改说明
- 精准过滤循环节点:直接在
for-each的select属性中筛选符合前缀条件的<str>节点,避免遍历所有节点后再判断,逻辑更高效; - 利用position()实现计数控制:在过滤后的节点集合中,
position()返回当前节点在该集合中的位置,直接判断位置是否小于等于目标数量即可实现取前N个的需求; - 简化节点引用:循环内部用
.指代当前节点,无需重复写全路径,同时修正了原代码中的拼写错误xsl:valus-of改为xsl:value-of; - 结构优化:将两次全量遍历改为两次精准过滤后的遍历,代码逻辑更清晰易读。
内容的提问来源于stack exchange,提问作者Kannan Arumugam
相关产品推荐
相关产品推荐

