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

如何通过XSLT的for-each将批量元素归集到单个Batch元素中

XSLT批量记录归集到单Batch元素修复方案

问题根因

现有逐<Test>节点遍历生成<Batch>的逻辑是单Test节点对单Batch的1:1映射,未做批次维度的归组处理,必然导致同批次的BatchH、Entry、NOC、BatchC节点分散到多个独立的Batch元素中,同时因为遍历逻辑未做空值判断、层级对齐处理,会衍生空Batch标签、节点嵌套错误问题。

修复核心逻辑

  • 以批次唯一标识(通常为BatchH下的批次号字段,可根据自身XSD定义调整)为维度做分组,而非逐Test节点生成Batch
  • 单个分组(单个批次)仅生成1个<Batch>父元素,父元素内部严格按照目标XSD要求的顺序归集子节点:先写入批次头BatchH,再批量写入该批次下所有Entry、NOC记录,最后写入批次尾BatchC
  • 所有节点写入前做存在性校验,过滤空内容,从根源避免空标签生成

可直接复用的代码实现

XSLT 2.0及以上版本(大部分SOA集成场景默认支持)

直接用内置的xsl:for-each-group标签实现分组,逻辑简洁性能更好:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" encoding="UTF-8" omit-xml-declaration="no"/>

  <!-- 匹配源XML根节点,根节点名称可根据实际源XSD调整 -->
  <xsl:template match="/SourceRoot">
    <!-- 目标XML根节点,可根据实际目标XSD调整 -->
    <TargetRoot>
      <!-- 按批次唯一键分组,此处group-by字段替换为自身Schema里的批次唯一标识即可 -->
      <xsl:for-each-group select="Test" group-by="BatchH/BatchNumber">
        <Batch>
          <!-- 写入当前批次头,取分组内第一个Test节点下的BatchH即可 -->
          <xsl:copy-of select="current-group()[1]/BatchH"/>
          <!-- 归集当前批次下所有Entry记录 -->
          <xsl:for-each select="current-group()/Entry[normalize-space(.) != '']">
            <xsl:copy-of select="."/>
          </xsl:for-each>
          <!-- 归集当前批次下所有NOC记录 -->
          <xsl:for-each select="current-group()/NOC[normalize-space(.) != '']">
            <xsl:copy-of select="."/>
          </xsl:for-each>
          <!-- 写入当前批次尾,取分组内最后一个Test节点下的BatchC即可 -->
          <xsl:copy-of select="current-group()[last()]/BatchC"/>
        </Batch>
      </xsl:for-each-group>
    </TargetRoot>
  </xsl:template>
</xsl:stylesheet>

XSLT 1.0版本兼容方案

如果运行环境仅支持XSLT 1.0,用Muenchian分组法替换分组逻辑即可,内部子节点归集逻辑和2.0版本一致:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" encoding="UTF-8"/>
  <!-- 定义批次分组键,use属性替换为自身Schema的批次唯一标识 -->
  <xsl:key name="batchGroupKey" match="Test" use="BatchH/BatchNumber"/>

  <xsl:template match="/SourceRoot">
    <TargetRoot>
      <!-- 遍历每个批次的首个Test节点,作为分组入口 -->
      <xsl:for-each select="//Test[generate-id() = generate-id(key('batchGroupKey', BatchH/BatchNumber)[1])]">
        <xsl:variable name="currentBatchId" select="BatchH/BatchNumber"/>
        <Batch>
          <xsl:copy-of select="BatchH"/>
          <!-- 归集当前批次下所有非空Entry -->
          <xsl:for-each select="key('batchGroupKey', $currentBatchId)/Entry[normalize-space(.) != '']">
            <xsl:copy-of select="."/>
          </xsl:for-each>
          <!-- 归集当前批次下所有非空NOC -->
          <xsl:for-each select="key('batchGroupKey', $currentBatchId)/NOC[normalize-space(.) != '']">
            <xsl:copy-of select="."/>
          </xsl:for-each>
          <xsl:copy-of select="key('batchGroupKey', $currentBatchId)[last()]/BatchC"/>
        </Batch>
      </xsl:for-each>
    </TargetRoot>
  </xsl:template>
</xsl:stylesheet>

校验规则

转换完成后对照以下规则校验,确保输出符合XSD要求:

  • 每个批次仅对应1个<Batch>父元素,无重复、无遗漏
  • Batch内子节点顺序严格匹配目标XSD要求:BatchH → Entry → NOC → BatchC,无嵌套错位
  • 无空<Batch>标签、无空白无效子节点
  • 所有节点命名、层级完全对齐目标XSD定义

如果你的源XML里批次唯一标识字段、节点命名和示例有差异,直接替换代码中对应字段、节点名即可,核心分组归组逻辑不需要调整。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 16:42:52