XSLT按自定义状态排序取最差值报错:xsl:sort不能在此处使用
解决XSLT中
xsl:sort位置错误及获取最差状态值的问题 问题背景
你需要根据给定的状态优先级(从优到差:0, 1, 2, 3, 4, 5, 6, G, U, Q, ., V, R, I, X, D),从一组<Details>节点中找出最差的状态(对应编码值最大的项)。你尝试通过编码状态为数字后排序取最大值,但遇到了错误:
Code: 0x80004005 Keyword xsl:sort may not be used here
错误原因
XSLT语法有明确要求:xsl:sort必须是xsl:for-each或xsl:apply-templates的第一个直接子元素。你的代码中,xsl:for-each内部先定义了$Status变量,之后才放置xsl:sort,这违反了语法规则,导致报错。
解决方案
方案1:XSLT 1.0兼容版本
调整xsl:for-each的结构,将xsl:sort放在最前面,直接使用模板返回的编码值作为排序键,然后取排序后的第一个元素的编码:
<xsl:variable name="MaxWorstStatus"> <xsl:for-each select="//ic:Details/ic:status"> <!-- 把xsl:sort放在for-each的第一个子位置 --> <xsl:sort select="call-template('encodeStatus')" data-type="number" order="descending"/> <xsl:if test="position() = 1"> <xsl:call-template name="encodeStatus"> <xsl:with-param name="Node" select="."/> </xsl:call-template> </xsl:if> </xsl:for-each> </xsl:variable> <xsl:template name="encodeStatus"> <xsl:param name="Node"/> <xsl:choose> <xsl:when test="$Node='0'">0</xsl:when> <xsl:when test="$Node='1'">1</xsl:when> <xsl:when test="$Node='2'">2</xsl:when> <xsl:when test="$Node='3'">3</xsl:when> <xsl:when test="$Node='4'">4</xsl:when> <xsl:when test="$Node='5'">5</xsl:when> <xsl:when test="$Node='6'">6</xsl:when> <xsl:when test="$Node='G'">7</xsl:when> <xsl:when test="$Node='U'">8</xsl:when> <!-- 修正编码对应优先级顺序:G比U更优 --> <xsl:when test="$Node='Q'">9</xsl:when> <xsl:when test="$Node='.'">10</xsl:when> <xsl:when test="$Node='V'">11</xsl:when> <xsl:when test="$Node='R'">12</xsl:when> <xsl:when test="$Node='I'">13</xsl:when> <xsl:when test="$Node='X'">14</xsl:when> <xsl:when test="$Node='D'">15</xsl:when> <xsl:otherwise>0</xsl:otherwise> <!-- 默认设为最优,避免异常值干扰 --> </xsl:choose> </xsl:template>
注意:你之前的
encodeStatus模板中把U编码为7,但根据优先级顺序G在U前面(更优),所以修正了编码对应关系,确保排序逻辑和预期一致。
方案2:XSLT 2.0+简化版本
如果使用XSLT 2.0或更高版本,可以利用序列和max()函数,代码更简洁高效:
<xsl:variable name="status-map" as="map(xs:string, xs:integer)"> <xsl:map> <xsl:map-entry key="'0'" select="0"/> <xsl:map-entry key="'1'" select="1"/> <xsl:map-entry key="'2'" select="2"/> <xsl:map-entry key="'3'" select="3"/> <xsl:map-entry key="'4'" select="4"/> <xsl:map-entry key="'5'" select="5"/> <xsl:map-entry key="'6'" select="6"/> <xsl:map-entry key="'G'" select="7"/> <xsl:map-entry key="'U'" select="8"/> <xsl:map-entry key="'Q'" select="9"/> <xsl:map-entry key="'.'" select="10"/> <xsl:map-entry key="'V'" select="11"/> <xsl:map-entry key="'R'" select="12"/> <xsl:map-entry key="'I'" select="13"/> <xsl:map-entry key="'X'" select="14"/> <xsl:map-entry key="'D'" select="15"/> </xsl:map> </xsl:variable> <xsl:variable name="MaxWorstStatus" select="max(//ic:Details/ic:status/($status-map(.)))"/>
这个版本直接通过映射表将状态转换为数字,然后用max()函数一步获取最大值,无需排序,逻辑更清晰。
验证结果
修正后的代码会正确处理你的测试数据(状态值:U,0,X,D,1,2),返回对应D的编码15,完全符合预期。
内容的提问来源于stack exchange,提问作者Paul Nario
相关产品推荐
相关产品推荐

