XSLT 3.0流处理模板规则不可流化问题求助
解决SAXON流处理中模板不可流化的问题
问题根源
流处理模式下,同一个流节点只能被消费一次。你的代码中同时存在「检查是否存在item」和「遍历item」两个操作,相当于两次消费流;另外直接返回流节点的遍历结果也不符合流处理规则,最终触发Template rule is not streamable错误。
修复方案
使用SAXON支持的xsl:fork指令(XSLT 3.0特性),将「检查item是否存在」和「遍历item」的操作拆分到独立分支,避免重复消费流;同时确保输出为原子文本值,而非流节点。
修正后的XSLT代码
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text" encoding="UTF-8"/> <xsl:mode streamable="yes"/> <xsl:template match="/root"> <xsl:fork> <!-- 分支1:无item时输出默认行 --> <xsl:sequence> <xsl:if test="not(exists(item))"> <xsl:text>default_id,default_name,default_value </xsl:text> </xsl:if> </xsl:sequence> <!-- 分支2:遍历item输出对应行 --> <xsl:sequence> <xsl:for-each select="item"> <xsl:value-of select="concat(id, ',', name, ',', value, ' ')"/> </xsl:for-each> </xsl:sequence> </xsl:fork> </xsl:template> </xsl:stylesheet>
关键说明
xsl:fork会复制输入流到多个分支,每个分支可独立消费流,规避重复读取的问题。- 所有输出都通过
xsl:text或concat转换为字符串原子值,符合流处理对结果的要求。 - 保留
xsl:mode streamable="yes"开启流处理模式。
示例验证
含item的XML输入
<root> <item> <id>1</id> <name>test1</name> <value>val1</value> </item> <item> <id>2</id> <name>test2</name> <value>val2</value> </item> </root>
输出结果:
1,test1,val1 2,test2,val2
不含item的XML输入
<root> <!-- 无item元素 --> </root>
输出结果:
default_id,default_name,default_value
备选方案(不依赖xsl:fork)
若无法使用xsl:fork,可先将item节点加载到内存变量(注意大体积XML可能占用较多内存),再进行判断:
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text" encoding="UTF-8"/> <xsl:mode streamable="yes"/> <xsl:template match="/root"> <xsl:variable name="items" select="item" as="node()*"/> <xsl:choose> <xsl:when test="not($items)"> <xsl:text>default_id,default_name,default_value </xsl:text> </xsl:when> <xsl:otherwise> <xsl:for-each select="$items"> <xsl:value-of select="concat(id, ',', name, ',', value, ' ')"/> </xsl:for-each> </xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet>
内容的提问来源于stack exchange,提问作者Gopinath
相关产品推荐
相关产品推荐

