多ITEM场景下XSLT排序报错及解决方案咨询
问题解决:XSLT排序多LINE的ITEM时fn:concat()序列错误
问题背景
需对XML中三类元素按以下规则排序:
- Node/ITEM(单LINE场景):ITEM仅含1个LINE,Key1值重复时按Key2、BNUMBER排序
- Node/ITEM(多LINE场景):ITEM含2个及以上LINE,排序规则同单LINE场景
- Node/LINE:按Key1分组后,按Key2、BNUMBER排序
现有XSLT在处理多LINE的ITEM时抛出错误:A sequence of more than one item is not allowed as the first argument of fn:concat() (<BNUMBER>, <BNUMBER>)
错误原因
当ITEM包含多个LINE时,直接引用ITEM/LINE/BNUMBER会返回多节点序列,而fn:concat()要求每个参数为单一值,无法处理多节点输入,因此触发报错。
解决方案
核心思路是先对每个ITEM内的LINE按规则排序,再基于排序后的首个LINE的Key1、Key2、BNUMBER生成ITEM的排序键,确保传入concat()的是单一值,同时满足所有排序规则。
修正后的XSLT代码
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <!-- 处理Node节点,实现ITEM和LINE的双重排序 --> <xsl:template match="Node"> <Node> <!-- 排序所有ITEM --> <xsl:for-each select="ITEM"> <!-- 基于ITEM内排序后的首个LINE生成排序键 --> <xsl:sort select="concat( normalize-space(sort(LINE, $key1-sort)[1]/Key1), '|', normalize-space(sort(LINE, $key2-sort)[1]/Key2), '|', normalize-space(sort(LINE, $bnum-sort)[1]/BNUMBER) )" order="ascending"/> <ITEM> <!-- 对当前ITEM内的LINE按规则排序 --> <xsl:for-each select="LINE"> <xsl:sort select="Key1" order="ascending"/> <xsl:sort select="Key2" order="ascending"/> <xsl:sort select="BNUMBER" order="ascending"/> <xsl:copy-of select="."/> </xsl:for-each> </ITEM> </xsl:for-each> </Node> </xsl:template> <!-- 定义排序函数,简化代码 --> <xsl:function name="key1-sort" as="xs:string"> <xsl:param name="line" as="element(LINE)"/> <xsl:sequence select="$line/Key1"/> </xsl:function> <xsl:function name="key2-sort" as="xs:string"> <xsl:param name="line" as="element(LINE)"/> <xsl:sequence select="$line/Key2"/> </xsl:function> <xsl:function name="bnum-sort" as="xs:string"> <xsl:param name="line" as="element(LINE)"/> <xsl:sequence select="$line/BNUMBER"/> </xsl:function> <!-- 默认复制模板,保留其他节点结构 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
输入示例XML
<Root> <Node> <ITEM> <LINE> <Key1>A</Key1> <Key2>2</Key2> <BNUMBER>002</BNUMBER> </LINE> <LINE> <Key1>A</Key1> <Key2>1</Key2> <BNUMBER>001</BNUMBER> </LINE> </ITEM> <ITEM> <LINE> <Key1>A</Key1> <Key2>1</Key2> <BNUMBER>001</BNUMBER> </LINE> </ITEM> <ITEM> <LINE> <Key1>B</Key1> <Key2>1</Key2> <BNUMBER>001</BNUMBER> </LINE> </ITEM> </Node> </Root>
期望输出XML
<Root> <Node> <ITEM> <LINE> <Key1>A</Key1> <Key2>1</Key2> <BNUMBER>001</BNUMBER> </LINE> <LINE> <Key1>A</Key1> <Key2>2</Key2> <BNUMBER>002</BNUMBER> </LINE> </ITEM> <ITEM> <LINE> <Key1>A</Key1> <Key2>1</Key2> <BNUMBER>001</BNUMBER> </LINE> </ITEM> <ITEM> <LINE> <Key1>B</Key1> <Key2>1</Key2> <BNUMBER>001</BNUMBER> </LINE> </ITEM> </Node> </Root>
关键说明
- 先对ITEM内的LINE按规则排序,取排序后的首个LINE的属性生成ITEM的排序键,确保
concat()接收单一值,解决序列错误问题 - 同时对每个ITEM内的LINE单独排序,满足Node/LINE的分组排序规则
- 兼容单LINE和多LINE的ITEM场景,完全匹配需求中的排序规则
内容的提问来源于stack exchange,提问作者Pavan
相关产品推荐
相关产品推荐

