XSLT遍历子节点时如何按顺序将每个节点重复输出两次
XSLT遍历子节点时实现单节点内容重复输出多次
需求:遍历子节点时,每个子节点对应的内容连续重复输出2次,再处理下一个子节点。例如示例中apple对应内容连续输出2次后,再输出2次mango的对应内容。
输入XML
<?xml version="1.0" encoding="Windows-1252" standalone="no"?> <root > <child id="123"> <fruit>apple</fruit> <comment>This is 1st line</comment> </child> <child id="345"> <fruit>mango</fruit> <comment>This is 2nd line</comment> </child> </root>
原有问题代码
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0"> <xsl:output indent="yes" /> <xsl:template match="/"> <xsl:param name="pack" select="2"></xsl:param> <xsl:for-each select="root/child"> <xsl:for-each select="(//node())[position() <= $pack]"> <xsl:text>
</xsl:text> <xsl:value-of select="//fruit"/> <xsl:text>
</xsl:text> <xsl:value-of select="//comment"/> <xsl:text>
</xsl:text> </xsl:for-each> </xsl:for-each> </xsl:template> </xsl:stylesheet>
实际错误输出
apple This is 1st line apple This is 1st line apple This is 1st line apple This is 1st line
预期输出
apple This is 1st line apple This is 1st line mango This is 2nd line mango This is 2nd line
问题根因
- 内层循环使用
(//node())选取全文档所有节点,不是用来实现固定次数重复的循环逻辑 - 取值时用了绝对路径
//fruit、//comment,无论外层遍历到哪个child节点,永远匹配全文档第一个对应元素,所以所有输出都是第一个子节点的apple内容
修复代码
XSLT 1.0 兼容版本(递归实现循环)
XSLT 1.0没有原生的序列生成语法,通过递归命名模板实现固定次数重复,取值时用相对路径匹配当前遍历的子节点即可:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="text" indent="yes" /> <!-- 配置单节点重复输出次数 --> <xsl:param name="pack" select="2"/> <xsl:template match="/"> <xsl:for-each select="root/child"> <xsl:variable name="currentNode" select="."/> <xsl:call-template name="loopPrint"> <xsl:with-param name="remainTimes" select="$pack"/> <xsl:with-param name="node" select="$currentNode"/> </xsl:call-template> </xsl:for-each> </xsl:template> <!-- 递归模板:实现N次重复输出 --> <xsl:template name="loopPrint"> <xsl:param name="remainTimes"/> <xsl:param name="node"/> <xsl:if test="$remainTimes > 0"> <xsl:value-of select="$node/fruit"/> <xsl:text>
</xsl:text> <xsl:value-of select="$node/comment"/> <xsl:text>
</xsl:text> <xsl:call-template name="loopPrint"> <xsl:with-param name="remainTimes" select="$remainTimes - 1"/> <xsl:with-param name="node" select="$node"/> </xsl:call-template> </xsl:if> </xsl:template> </xsl:stylesheet>
XSLT 2.0+ 简洁版本
2.0及以上版本支持直接用1 to N生成数字序列做循环,不需要递归:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> <xsl:output method="text" indent="yes" /> <xsl:param name="pack" select="2"/> <xsl:template match="/"> <xsl:for-each select="root/child"> <xsl:variable name="cur" select="."/> <xsl:for-each select="1 to $pack"> <xsl:value-of select="$cur/fruit"/> <xsl:text>
</xsl:text> <xsl:value-of select="$cur/comment"/> <xsl:text>
</xsl:text> </xsl:for-each> </xsl:for-each> </xsl:template> </xsl:stylesheet>
内容的提问来源于stack exchange,提问作者Akash
相关产品推荐
相关产品推荐

