You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:使用XSLT对相同MAT值的ROOT段按FIELD3排序

XSLT分组排序问题:仅对相同MAT值的ROOT段按FIELD3排序,其余节点保持原位置

需求说明

我需要实现以下XSLT转换逻辑:

  • 当XML中存在多个<ROOT>节点且它们的<MAT>子元素值相同时,将这一组<ROOT>节点按<FIELD3>子元素的值排序
  • 所有其他节点(包括MAT值唯一的<ROOT>节点、非<ROOT>节点)均保持原有位置和结构不变

输入XML

<?xml version="1.0" encoding="UTF-8"?>
<HEADER>
   <DOC BEGIN="1"> 
          <EDI_40>
          <Field1>123</Field1>
          </EDI_40>   
          <E_E20>
         <ROOT SEGMENT="1">
            <POS>000020</POS>
            <MAT>1234</MAT>
            <FIELD3>4199</FIELD3>
            <QUAN>3420</QUAN>
            <CHILD SEGMENT="1">
               <POS>000010</POS>
               <PQ>UN</PQ>             
            </CHILD>            
         </ROOT>   
         <ROOT SEGMENT="1">
            <POS>000010</POS>
            <MAT>123456</MAT>
            <FIELD3>4199BI015</FIELD3>
            <QUAN>3420</QUAN>
            <CHILD SEGMENT="1">
               <POS>000010</POS>
               <PQ>UN1</PQ>             
            </CHILD>            
         </ROOT>
         <ROOT SEGMENT="1">
            <POS>000010</POS>
            <MAT>123456</MAT>
            <FIELD3>4184AI015</FIELD3>
            <QUAN>1026</QUAN>
           <CHILD SEGMENT="1">
               <POS>000010</POS>
               <PQ>UN2</PQ>            
            </CHILD> 
             <CHILD SEGMENT="1">
               <POS>000010</POS>
               <PQ>UN2</PQ>            
            </CHILD>            
         </ROOT>
         <ROOT SEGMENT="1">
            <POS>000010</POS>
            <MAT>123456</MAT>
            <FIELD3>4200AI015</FIELD3>
            <QUAN>1197</QUAN>
             <CHILD SEGMENT="1">
               <POS>000010</POS>
               <PQ>UN3</PQ>             
            </CHILD>           
         </ROOT>
              <ROOT SEGMENT="1">
            <POS>000030</POS>
            <MAT>123</MAT>
            <FIELD3>4200AI</FIELD3>
            <QUAN>1197</QUAN>
             <CHILD SEGMENT="1">
               <POS>000010</POS>
               <PQ>UN</PQ>             
            </CHILD>           
         </ROOT>
         </E_E20>
   </DOC>
</HEADER>

预期输出XML

<?xml version="1.0" encoding="UTF-8"?>
<HEADER>
   <DOC BEGIN="1">  
          <EDI_40>
          <Field1>123</Field1>
          </EDI_40>   
          <E_E20>
         <ROOT SEGMENT="1">
            <POS>000020</POS>
            <MAT>1234</MAT>
            <FIELD3>4199</FIELD3>
            <QUAN>3420</QUAN>
            <CHILD SEGMENT="1">
               <POS>000010</POS>
               <PQ>UN</PQ>             
            </CHILD>            
         </ROOT> 

         <ROOT SEGMENT="1">
            <POS>000010</POS>
            <MAT>123456</MAT>
            <FIELD3>4184AI015</FIELD3>
            <QUAN>1026</QUAN>
           <CHILD SEGMENT="1">
               <POS>000010</POS>
               <PQ>UN2</PQ>            
            </CHILD> 
             <CHILD SEGMENT="1">
               <POS>000010</POS>
               <PQ>UN2</PQ>            
            </CHILD>            
         </ROOT>         
         <ROOT SEGMENT="1">
            <POS>000010</POS>
            <MAT>123456</MAT>
            <FIELD3>4199BI015</FIELD3>
            <QUAN>3420</QUAN>
            <CHILD SEGMENT="1">
               <POS>000010</POS>
               <PQ>UN1</PQ>             
            </CHILD>            
         </ROOT>
         
         <ROOT SEGMENT="1">
            <POS>000010</POS>
            <MAT>123456</MAT>
            <FIELD3>4200AI015</FIELD3>
            <QUAN>1197</QUAN>
             <CHILD SEGMENT="1">
               <POS>000010</POS>
               <PQ>UN3</PQ>             
            </CHILD>           
         </ROOT>
              <ROOT SEGMENT="1">
            <POS>000030</POS>
            <MAT>123</MAT>
            <FIELD3>4200AI</FIELD3>
            <QUAN>1197</QUAN>
             <CHILD SEGMENT="1">
               <POS>000010</POS>
               <PQ>UN</PQ>             
            </CHILD>           
         </ROOT>
          </E_E20>
   </DOC>
</HEADER>

我使用的错误XSLT

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="//ROOT">
<ROOT>
<xsl:for-each select="distinct-values(//ROOT/@MAT)">
<xsl:sort select="." data-type="number"/>
<xsl:apply-templates select="//ROOT/FIELD3[@MAT = current()]"/>
</xsl:for-each>
</ROOT>
</xsl:template>
<xsl:template match="HEADER">
<xsl:copy/>
</xsl:template>
 
</xsl:stylesheet>

错误分析

  1. 模板匹配逻辑错误:匹配//ROOT会导致每个<ROOT>节点被重复处理,完全偏离需求逻辑
  2. 节点选择错误:MAT是<ROOT>的子元素而非属性,原代码中//ROOT/@MAT、//ROOT/FIELD3[@MAT = current()]的写法完全错误
  3. 节点复制不完整:匹配HEADER的模板仅执行<xsl:copy/>,未复制任何子节点,导致大部分内容丢失

正确的XSLT解决方案

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <!-- 身份模板:默认复制所有节点和属性,保证非目标节点的结构不变 -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <!-- 专门处理E_E20节点,对其子节点进行分组排序 -->
    <xsl:template match="E_E20">
        <xsl:copy>
            <!-- 遍历E_E20的所有子节点,按规则分组 -->
            <xsl:for-each-group select="*" group-by="if (self::ROOT) then MAT else generate-id()">
                <!-- 按组中第一个元素的原始位置排序,保证整体顺序与原文档一致 -->
                <xsl:sort select="index-of(current()/*, .)" data-type="number"/>
                
                <xsl:choose>
                    <!-- 处理ROOT节点分组:组内按FIELD3排序后输出 -->
                    <xsl:when test="self::ROOT">
                        <xsl:apply-templates select="current-group()">
                            <xsl:sort select="FIELD3"/>
                        </xsl:apply-templates>
                    </xsl:when>
                    <!-- 非ROOT节点直接输出,保持原位置 -->
                    <xsl:otherwise>
                        <xsl:apply-templates select="current-group()"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

代码说明

  1. 身份模板:作为基础模板,负责复制所有未被特殊模板匹配的节点和属性,确保原XML的大部分结构和内容保持不变
  2. E_E20节点处理:
    • 对<E_E20>的所有子节点分组:<ROOT>节点按<MAT>值分组,非<ROOT>节点每个单独成组(用generate-id()保证唯一性)
    • 按组的原始出现顺序排序,确保整体结构与原文档一致
    • 对<ROOT>分组内的节点,按<FIELD3>的值排序后输出;非<ROOT>分组直接输出,保持原位置
  3. 兼容性:基于XSLT 2.0语法,需使用支持XSLT 2.0的处理器(如Saxon)

内容的提问来源于stack exchange,提问作者Anu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 06:50:54