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

如何用XSLT合并两个XML文件并去重?附现有代码求指导

邮件列表与用户列表的合并问题及解决方案

现有文件内容

1. users-list.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE users SYSTEM "user-list.dtd">
<users>
    <user>
        <forename>Joe</forename>
        <surname>Bloggs</surname>
        <email>j.bloggs@sample.co.uk</email>
    </user>
    <user>
        <forename>Winston</forename>
        <surname>Smith</surname>
        <email>w.smith@airstripOne.gov</email>
    </user>
    ...
</users>

2. mailing-list.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mailingList SYSTEM "mailing-list.dtd">
<mailingList>
    <subscriber familyname="Smith"
                givenname="John"
                email="john.smith@somewhere.com"/>
    <subscriber givenname="Luke"
                familyname="Skywalker"
                email="son.of.darth@tatooine.com"/>
    ...
</mailingList>

需求说明

将mailing-list.xml中的订阅者合并到users-list.xml中,仅添加用户列表中不存在对应邮箱的条目,同时要把订阅者的属性格式(givenname/familyname/email属性)转换成用户列表的子元素格式(forename/surname/email子元素)。

当前XSLT的问题点

你写的merge.xslt已经有了正确的核心思路,但存在几个关键错误:

  • 多余的自定义DOCTYPE声明:XSLT样式文件不需要这个冗余内容
  • 加载外部XML错误:document('')是读取当前XSLT文件本身,而非目标的mailing-list.xml
  • 跨文档键索引失效:XSLT 1.0中,xsl:key默认只能索引当前上下文的文档,无法同时索引两个不同的XML文件,原有的key判断逻辑不生效
  • 筛选订阅者的表达式错误:受上述问题影响,not(key('emails', @email, /users))无法正确判断邮箱是否存在

修正后的XSLT代码

<?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" version="1.0" encoding="UTF-8" indent="yes"/>

    <!-- 处理根节点users,生成合并后的users列表 -->
    <xsl:template match="/users">
        <users>
            <!-- 复制原用户列表的所有user元素 -->
            <xsl:apply-templates select="user"/>
            <!-- 加载mailing-list.xml,筛选出邮箱不在原用户列表中的subscriber -->
            <xsl:apply-templates 
                select="document('mailing-list.xml')/mailingList/subscriber
                        [not(/users/user/email = current()/@email)]"/>
        </users>
    </xsl:template>

    <!-- 复制原user元素及其所有内容 -->
    <xsl:template match="user">
        <user>
            <xsl:apply-templates select="@*|node()"/>
        </user>
    </xsl:template>

    <!-- 将subscriber转换为user格式 -->
    <xsl:template match="subscriber">
        <user>
            <forename><xsl:value-of select="@givenname"/></forename>
            <surname><xsl:value-of select="@familyname"/></surname>
            <email><xsl:value-of select="@email"/></email>
        </user>
    </xsl:template>
</xsl:stylesheet>

关键修正说明

  • 移除了冗余的DOCTYPE声明,保持XSLT文件简洁
  • 使用document('mailing-list.xml')正确加载外部邮件列表文件(注意文件路径要与XSLT文件同级,或使用正确的相对/绝对路径)
  • 调整订阅者筛选逻辑:通过not(/users/user/email = current()/@email)直接检查当前订阅者的邮箱是否在原用户列表中不存在,避开了XSLT1.0跨文档键索引的限制
  • 保留了你原本正确的模板逻辑:复制原用户、转换订阅者格式为用户格式

内容的提问来源于stack exchange,提问作者Harry Turner-Burns

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 09:45:02