如何用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
相关产品推荐
相关产品推荐

