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

如何用XSLT 1.0/2.0移除XML重复Row节点并合并字段?

问题:基于MemberAltId和PatientSeqId去重Row并合并字段

我有一份XML源文件,需要根据MemberAltId和PatientSeqId两个子节点去除重复的Row记录,并合并同一组的不同字段。作为XSLT初学者,我尝试了XSLT 1.0和2.0的多种实现方式,但都未达到预期效果。以下是我的源XML、尝试的代码及期望输出,求可行解决方案:

源XML

<?xml version="1.0" encoding="UTF-8"?>
<DataSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <EDI.Table name="EDI.Table">
        <Row>
            <GroupId>A</GroupId>
            <MemberAltId>ABC123</MemberAltId>
            <PatientSeqId>002</PatientSeqId>
            <TotalMemberDeductible>499.52</TotalMemberDeductible>
        </Row>
        <Row>
            <GroupId>A</GroupId>
            <MemberAltId>ABC123</MemberAltId>
            <PatientSeqId>002</PatientSeqId>
            <TotalMemberOop>499.52</TotalMemberOop>
        </Row>
        <Row>
            <GroupId>A</GroupId>
            <MemberAltId>DEF123</MemberAltId>
            <PatientSeqId>001</PatientSeqId>
            <TotalMemberOop>50.00</TotalMemberOop>
        </Row>
    </EDI.Table>
</DataSet>

尝试的XSLT 1.0代码

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:key name="kMemberId" match="//Row" use="concat(MemberAltId,'|',PatientSeqId)"/>

<xsl:template match="/EDI.Table">
    <root>
        <xsl:for-each select="//Row[generate-id() = generate-id(key('kMemberId',concat(MemberAltId,'|',PatientSeqId))[1])]">
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
        </xsl:for-each>
    </root>
</xsl:template>

<xsl:template match="@*|node()">
    <xsl:copy>
               <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

尝试的XSLT 2.0代码

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output method="xml" indent="yes" />

<xsl:template match="/EDI.Table">
    <xsl:copy>
        <xsl:copy-of select="@* | Row"/>
        <xsl:for-each-group select="Row" group-by="MemberAltId">
            <xsl:for-each-group select="current-group()" group-by="PatientSeqId">
               <xsl:copy-of select="current-group()[1]"/>
          </xsl:for-each-group>
        </xsl:for-each-group>
    </xsl:copy>
</xsl:template>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

期望输出XML

<?xml version="1.0" encoding="UTF-8"?>
<DataSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <EDI.Table name="EDI.Table">
        <Row>
            <GroupId>A</GroupId>
            <MemberAltId>ABC123</MemberAltId>
            <PatientSeqId>002</PatientSeqId>
            <TotalMemberDeductible>499.52</TotalMemberDeductible>
            <TotalMemberOop>499.52</TotalMemberOop>
        </Row>
        <Row>
            <GroupId>A</GroupId>
            <MemberAltId>DEF123</MemberAltId>
            <PatientSeqId>001</PatientSeqId>
            <TotalMemberOop>50.00</TotalMemberOop>
        </Row>
    </EDI.Table>
</DataSet>

解决方案

XSLT 1.0 正确实现

原1.0代码存在两个核心问题:一是模板匹配路径错误(根节点为DataSet,原模板匹配/EDI.Table导致未触发);二是仅复制分组后第一个Row的原有节点,未合并同组内的其他字段。

正确代码:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <!-- 定义分组键:MemberAltId+PatientSeqId的组合 -->
    <xsl:key name="rowGroup" match="Row" use="concat(MemberAltId, '|', PatientSeqId)"/>

    <!-- 基础复制模板,保留原始XML结构 -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <!-- 处理EDI.Table节点,分组合并Row -->
    <xsl:template match="EDI.Table">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <!-- 筛选每个分组的第一个Row作为代表 -->
            <xsl:for-each select="Row[generate-id() = generate-id(key('rowGroup', concat(MemberAltId, '|', PatientSeqId))[1])]">
                <Row>
                    <!-- 输出当前分组内所有Row的子节点,实现字段合并 -->
                    <xsl:apply-templates select="key('rowGroup', concat(MemberAltId, '|', PatientSeqId))/*"/>
                </Row>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

XSLT 2.0 正确实现

原2.0代码的问题包括:模板匹配路径错误、复制了原始Row导致重复、仅保留组内第一个Row未合并字段。利用XSLT2.0的for-each-group可以更简洁实现分组合并:

正确代码:

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

    <!-- 基础复制模板 -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <!-- 分组合并Row -->
    <xsl:template match="EDI.Table">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <!-- 直接按MemberAltId+PatientSeqId的组合分组 -->
            <xsl:for-each-group select="Row" group-by="concat(MemberAltId, '|', PatientSeqId)">
                <Row>
                    <!-- 输出组内所有Row的子节点 -->
                    <xsl:apply-templates select="current-group()/*"/>
                </Row>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

关键说明

  • 两种实现均保留了原始XML的完整结构(包括DataSet、EDI.Table的属性);
  • 通过concat(MemberAltId, '|', PatientSeqId)生成唯一分组键,确保同一用户的同序列Row被归为一组;
  • 合并时输出组内所有Row的子节点,自动整合不同字段(若同组存在重复字段名,会保留最后出现的字段值,你的场景中无重复字段,无需额外处理)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 22:42:32