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

XSLT 1.0双层嵌套排序求助:WorkingQueue与ValidationAction排序

实现XML双层嵌套排序:按WorkingQueue@queueId升序后再按ValidationAction@actionLabel升序

问题背景

我之前用Sandy给的方案跑起来没问题,但后来代码嵌套层级变深了,现在要搞个双层嵌套排序:先把<WorkingQueue>按@queueId(数字从小到大)排,然后每个<WorkingQueue>下面的<ValidationAction>再按@actionLabel(字母顺序从小到大)排。试了好多次都没成功,目前手里有两个单独用都好使的模板,想把它们整合起来。

现有可单独生效的模板

  1. 只处理WorkingQueue排序的模板:
<xsl:template match="@*|node()">
  <xsl:copy>
    <xsl:apply-templates select="@*|node()"/>
  </xsl:copy>
</xsl:template>
<xsl:template match="WorkingQueues">
  <xsl:copy>
    <xsl:for-each select="WorkingQueue">
      <xsl:sort select="@queueId" order="ascending" data-type="number"/>
      <xsl:copy>
        <xsl:copy-of select="@*|node()"/>
      </xsl:copy>
    </xsl:for-each>
  </xsl:copy>
</xsl:template>
  1. 只处理ValidationAction排序的模板:
<xsl:template match="Actions">
  <xsl:copy>
    <xsl:for-each select="ValidationAction">
      <xsl:sort select="@actionLabel" order="ascending"/>
      <xsl:copy>
        <xsl:copy-of select="@*|node()"/>
      </xsl:copy>
    </xsl:for-each>
  </xsl:copy>
</xsl:template>

输入XML示例

<Export>
  <WorkingTemplates>
    <WorkingTemplate label="MM_DR">
      <WorkingQueues>
        <WorkingQueue queueId="132" right="READ_WRITE">
          <Actions>
            <ValidationAction actionLabel="BrkNotOk" enabled="true"/>
            <ValidationAction actionLabel="AddComment" enabled="true"/>
          </Actions>
        </WorkingQueue>
        <WorkingQueue queueId="49" right="READ_WRITE">
          <Actions>
            <ValidationAction actionLabel="BrkNotOk" enabled="true"/>
            <ValidationAction actionLabel="AddComment" enabled="true"/>
          </Actions>
        </WorkingQueue>
      </WorkingQueues>
    </WorkingTemplate>
    <WorkingTemplate label="FX_MA">
      <WorkingQueues>
        <WorkingQueue queueId="123" right="READ_WRITE">
          <Actions>
            <ValidationAction actionLabel="BrkNotOk" enabled="true"/>
            <ValidationAction actionLabel="AddComment" enabled="true"/>
          </Actions>
        </WorkingQueue>
        <WorkingQueue queueId="60" right="READ_WRITE">
          <Actions>
            <ValidationAction actionLabel="Accept" enabled="true"/>
          </Actions>
        </WorkingQueue>
      </WorkingQueues>
    </WorkingTemplate>
  </WorkingTemplates>
</Export>

期望输出结果

<Export>
  <WorkingTemplates>
    <WorkingTemplate label="MM_DR">
      <WorkingQueues>
        <WorkingQueue queueId="49" right="READ_WRITE">
          <Actions>
            <ValidationAction actionLabel="AddComment" enabled="true"/>
            <ValidationAction actionLabel="BrkNotOk" enabled="true"/>
          </Actions>
        </WorkingQueue>
        <WorkingQueue queueId="132" right="READ_WRITE">
          <Actions>
            <ValidationAction actionLabel="AddComment" enabled="true"/>
            <ValidationAction actionLabel="BrkNotOk" enabled="true"/>
          </Actions>
        </WorkingQueue>
      </WorkingQueues>
    </WorkingTemplate>
    <WorkingTemplate label="FX_MA">
      <WorkingQueues>
        <WorkingQueue queueId="60" right="READ_WRITE">
          <Actions>
            <ValidationAction actionLabel="Accept" enabled="true"/>
          </Actions>
        </WorkingQueue>
        <WorkingQueue queueId="123" right="READ_WRITE">
          <Actions>
            <ValidationAction actionLabel="AddComment" enabled="true"/>
            <ValidationAction actionLabel="BrkNotOk" enabled="true"/>
          </Actions>
        </WorkingQueue>
      </WorkingQueues>
    </WorkingTemplate>
  </WorkingTemplates>
</Export>

解决方案

其实很简单,把两个模板整合到同一个XSLT文件里就行,不过有个关键细节要改——原来的WorkingQueues模板里用了<xsl:copy-of>,这个会直接复制节点内容,不会触发其他模板的匹配,得改成<xsl:apply-templates>才能让内层的Actions排序模板生效。

整合后的完整XSLT代码:

<xsl:stylesheet version="1.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>

    <!-- 处理WorkingQueues:按queueId数字升序排列子WorkingQueue -->
    <xsl:template match="WorkingQueues">
        <xsl:copy>
            <xsl:for-each select="WorkingQueue">
                <xsl:sort select="@queueId" order="ascending" data-type="number"/>
                <xsl:copy>
                    <!-- 用apply-templates递归处理子节点,这样才能触发Actions的排序模板 -->
                    <xsl:apply-templates select="@*|node()"/>
                </xsl:copy>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>

    <!-- 处理Actions:按actionLabel字符升序排列子ValidationAction -->
    <xsl:template match="Actions">
        <xsl:copy>
            <xsl:for-each select="ValidationAction">
                <xsl:sort select="@actionLabel" order="ascending"/>
                <xsl:copy>
                    <xsl:copy-of select="@*|node()"/>
                </xsl:copy>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

核心细节解释

为什么要把copy-of改成apply-templates?因为:

  • copy-of是“无脑复制”,直接把节点及其内容原样输出,不会去检查有没有对应的模板可以处理子节点;
  • apply-templates是“按需处理”,会递归遍历当前节点的所有子节点和属性,遇到匹配的模板就用对应的逻辑处理——这样当处理到WorkingQueue下的Actions节点时,就会自动调用我们写的Actions排序模板,实现内层的ValidationAction排序。

用这个XSLT处理你的输入XML,就能得到你想要的双层排序结果啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:45:36