如何在XSLT 1.0中传递元素列表作为模板参数实现遍历?
解决XSLT 1.0中传递即时定义列表参数并遍历的问题
报错原因
在XSLT 1.0中,通过<xsl:with-param>传递的内嵌XML结构属于结果树片段(Result Tree Fragment, RTF),而非可直接遍历的节点集(Node Set)。XSLT 2.0会自动将这类结构视为节点集,所以你的代码在2.0中可行,但1.0中必须显式转换RTF为节点集才能遍历,这就是你遇到Invalid conversion from 'com.sun.org.apache.xalan.internal.xsltc.dom.SAXImpl' to 'node-set'错误的核心原因。
解决方案:用扩展函数转换RTF为节点集
Java项目常用Xalan作为XSLT处理器,可利用Xalan提供的xalan:nodeset()扩展函数完成转换。
步骤1:引入Xalan命名空间
在样式表根节点<xsl:stylesheet>中添加命名空间声明:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xalan="http://xml.apache.org/xalan">
步骤2:修改Parent模板的遍历逻辑
将原模板中的遍历目标改为转换后的节点集,指定要遍历的子节点(如你的<value>节点):
<xsl:template name="Parent"> <xsl:param name="element-list"/> <!-- 先将RTF转换为节点集,再遍历其中的value节点 --> <xsl:for-each select="xalan:nodeset($element-list)/element-list/value"> <xsl:call-template name="Child"> <!-- 传递当前value节点的文本或节点本身 --> <xsl:with-param name="element" select="."/> </xsl:call-template> </xsl:for-each> </xsl:template>
完整代码示例
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xalan="http://xml.apache.org/xalan"> <xsl:template name="Child"> <xsl:param name="element"/> <!-- 这里编写Child模板的处理逻辑,示例为输出元素内容 --> <p>处理元素:<xsl:value-of select="$element"/></p> </xsl:template> <xsl:template name="Parent"> <xsl:param name="element-list"/> <xsl:for-each select="xalan:nodeset($element-list)/element-list/value"> <xsl:call-template name="Child"> <xsl:with-param name="element" select="."/> </xsl:call-template> </xsl:for-each> </xsl:template> <!-- 调用示例 --> <xsl:template match="/"> <xsl:call-template name="Parent"> <xsl:with-param name="element-list"> <element-list type="array"> <value>FirstElement</value> <value>SecondElement</value> </element-list> </xsl:with-param> </xsl:call-template> </xsl:template> </xsl:stylesheet>
替代方案:用分隔字符串传递列表(无需扩展函数)
如果无法依赖处理器扩展,可将列表以分隔字符串形式传递,通过递归模板拆分遍历:
代码示例
<xsl:template name="Parent"> <xsl:param name="element-string" select="''"/> <xsl:param name="delimiter" select="','"/> <!-- 提取第一个元素 --> <xsl:variable name="first-element" select="substring-before(concat($element-string, $delimiter), $delimiter)"/> <xsl:variable name="remaining-elements" select="substring-after($element-string, $delimiter)"/> <xsl:if test="$first-element != ''"> <xsl:call-template name="Child"> <xsl:with-param name="element" select="$first-element"/> </xsl:call-template> <!-- 递归处理剩余元素 --> <xsl:call-template name="Parent"> <xsl:with-param name="element-string" select="$remaining-elements"/> <xsl:with-param name="delimiter" select="$delimiter"/> </xsl:call-template> </xsl:if> </xsl:template> <!-- 调用示例 --> <xsl:call-template name="Parent"> <xsl:with-param name="element-string" select="'FirstElement,SecondElement'"/> </xsl:call-template>
这种方法仅适用于纯字符串列表,无需依赖扩展,但处理逻辑相对繁琐。
内容的提问来源于stack exchange,提问作者Marco Flavio Farella
相关产品推荐
相关产品推荐

