使用Saxon的XSLT 3.0流处理报错:存在多个消耗操作数
Saxon 11.2 XSLT 3.0流处理报错解决
问题说明
使用Saxon 11.2版本进行XSLT 3.0流处理时,同一模板中同时调用replace和contains字符串函数会触发报错:
Template rule is not streamable * There is more than one consuming operand
单独使用其中任意一个函数时,XSLT可正常运行。
示例输入XML
<?xml version="1.0" encoding="UTF-8"?> <Update xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <Request> <List> <RequestP><ManNumber>3B4</ManNumber></RequestP> <RequestP><ManNumber>8T7_BE</ManNumber></RequestP> <RequestP><ManNumber>3B5</ManNumber></RequestP> <RequestP><ManNumber>5E9_BE</ManNumber></RequestP> <RequestP><ManNumber>9X6</ManNumber></RequestP> </List> </Request> </Update>
原报错XSLT代码
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0" exclude-result-prefixes="#all"> <xsl:output method="xml" omit-xml-declaration="no" indent="yes" /> <xsl:mode streamable="yes" /> <xsl:template match="List/RequestP/ManNumber"> <ManNumber> <xsl:value-of select="replace(.,'_BE','')" /> </ManNumber> <xsl:if test="contains(.,'_BE')"> <ManDescrip>BE</ManDescrip> </xsl:if> </xsl:template> </xsl:stylesheet>
报错信息(中文翻译)
模板规则不支持流处理 * 存在多个消费操作数:第6行的{<ManNumber {xsl:value-of}/>},以及第9行的{if(fn:contains(...)) then ... else ...}
解决方案
流处理模式下,源节点只能被一次性消费(即读取其内容一次),replace和contains都会读取节点的字符串值,属于两次独立的消费操作,违反了流处理规则。
解决方法是先将节点的字符串值缓存到变量中,后续操作均使用该变量,确保只消费节点一次:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0" exclude-result-prefixes="#all"> <xsl:output method="xml" omit-xml-declaration="no" indent="yes" /> <xsl:mode streamable="yes" /> <xsl:template match="List/RequestP/ManNumber"> <!-- 缓存节点字符串值,仅消费节点一次 --> <xsl:variable name="manNumValue" select="string(.)"/> <ManNumber> <xsl:value-of select="replace($manNumValue, '_BE', '')" /> </ManNumber> <xsl:if test="contains($manNumValue, '_BE')"> <ManDescrip>BE</ManDescrip> </xsl:if> </xsl:template> </xsl:stylesheet>
原理说明
通过xsl:variable将节点的字符串值提取并缓存后,后续的replace和contains操作都基于变量值进行,不再重复读取源节点内容,符合XSLT 3.0流处理的“单次消费”要求,从而解决报错问题。
内容的提问来源于stack exchange,提问作者Chandra_S
相关产品推荐
相关产品推荐

