基于XSLT 3.0按applicationId及元素名分组去重XML的技术问询
按applicationId分组并去重子元素的XSLT解决方案
问题背景
输入XML如下:
<?xml version='1.0' encoding='UTF-8'?> <Applications> <Application> <applicationId>280</applicationId> <cust_IDCheckIDCollation> <Option> <id>197249</id> </Option> </cust_IDCheckIDCollation> <cust_overallduedilligencestatus> <Option> <id>197276</id> </Option> </cust_overallduedilligencestatus> </Application> <Application> <applicationId>292</applicationId> <cust_IDCheckIDCollation> <Option> <id>197249</id> </Option> </cust_IDCheckIDCollation> <cust_overallduedilligencestatus> <Option> <id>197276</id> </Option> </cust_overallduedilligencestatus> </Application> <Application> <applicationId>280</applicationId> <cust_OnlineReferenceCheck> <Option> <id>197249</id> </Option> </cust_OnlineReferenceCheck> <cust_overallduedilligencestatus> <Option> <id>197276</id> </Option> </cust_overallduedilligencestatus> </Application> <Application> <applicationId>292</applicationId> <cust_OnlineReferenceCheck> <Option> <id>197249</id> </Option> </cust_OnlineReferenceCheck> <cust_overallduedilligencestatus> <Option> <id>197276</id> </Option> </cust_overallduedilligencestatus> </Application> <Application> <applicationId>280</applicationId> <cust_AustralianWorkRights> <Option> <id>197250</id> </Option> </cust_AustralianWorkRights> <cust_overallduedilligencestatus> <Option> <id>197276</id> </Option> </cust_overallduedilligencestatus> </Application> <Application> <applicationId>292</applicationId> <cust_AustralianWorkRights> <Option> <id>197250</id> </Option> </cust_AustralianWorkRights> <cust_overallduedilligencestatus> <Option> <id>197276</id> </Option> </cust_overallduedilligencestatus> </Application> <Application> <applicationId>280</applicationId> <cust_NationalPoliceCheck> <Option> <id>197249</id> </Option> </cust_NationalPoliceCheck> <cust_overallduedilligencestatus> <Option> <id>197276</id> </Option> </cust_overallduedilligencestatus> </Application> <Application> <applicationId>292</applicationId> <cust_NationalPoliceCheck> <Option> <id>197249</id> </Option> </cust_NationalPoliceCheck> <cust_overallduedilligencestatus> <Option> <id>197276</id> </Option> </cust_overallduedilligencestatus> </Application> </Applications>
需求:先按applicationId对<Application>节点分组,再对每组内的子元素按元素名去重,最终输出合并后的XML,预期结果如下:
<Applications> <Application> <applicationId>280</applicationId> <cust_IDCheckIDCollation> <Option> <id>197249</id> </Option> </cust_IDCheckIDCollation> <cust_overallduedilligencestatus> <Option> <id>197276</id> </Option> </cust_overallduedilligencestatus> <cust_OnlineReferenceCheck> <Option> <id>197249</id> </Option> </cust_OnlineReferenceCheck> <cust_AustralianWorkRights> <Option> <id>197250</id> </Option> </cust_AustralianWorkRights> <cust_NationalPoliceCheck> <Option> <id>197249</id> </Option> </cust_NationalPoliceCheck> </Application> <Application> <applicationId>292</applicationId> <cust_IDCheckIDCollation> <Option> <id>197249</id> </Option> </cust_IDCheckIDCollation> <cust_overallduedilligencestatus> <Option> <id>197276</id> </Option> </cust_overallduedilligencestatus> <cust_OnlineReferenceCheck> <Option> <id>197249</id> </Option> </cust_OnlineReferenceCheck> <cust_AustralianWorkRights> <Option> <id>197250</id> </Option> </cust_AustralianWorkRights> <cust_NationalPoliceCheck> <Option> <id>197249</id> </Option> </cust_NationalPoliceCheck> </Application> </Applications>
原有XSLT 2.0代码的问题
编写的XSLT 2.0代码无法得到预期结果,核心问题是:
<xsl:element name="{current-grouping-key()}"> <xsl:value-of select="(current-group())[1]"/> </xsl:element>
<xsl:value-of>仅提取节点的文本内容,丢失了子元素结构(比如<Option>和<id>节点),导致输出中带嵌套结构的子节点无法完整保留。
XSLT 3.0的简便实现
基于原有分组逻辑,替换文本提取为完整节点复制,结合XSLT 3.0的语法特性,可实现简洁高效的解决方案:
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:template match="/Applications"> <xsl:copy> <!-- 按applicationId分组 --> <xsl:for-each-group select="Application" group-by="applicationId"> <xsl:copy> <!-- 对组内所有子元素按元素名去重 --> <xsl:for-each-group select="current-group()/*" group-by="node-name()"> <!-- 复制分组后的第一个完整节点(包含所有子元素) --> <xsl:copy-of select="current-group()[1]"/> </xsl:for-each-group> </xsl:copy> </xsl:for-each-group> </xsl:copy> </xsl:template> </xsl:stylesheet>
关键改进点
- 用
<xsl:copy-of>替代<xsl:value-of>,完整复制节点及其所有子元素、属性,保留原XML结构。 - 使用
node-name()代替name(),node-name()返回节点的QName,在有命名空间的场景下更严谨,无命名空间时效果一致。 - XSLT 3.0原生支持分组逻辑,代码无需额外扩展即可高效运行。
内容的提问来源于stack exchange,提问作者Madhu N G
相关产品推荐
相关产品推荐

