XSLT的for-each-group基于双字段分组失效问题求助
OIC中XSLT按双元素分组去重的问题解决
问题背景
在OIC应用中使用XSLT处理XML数据,需要基于DOC和DOCO两个元素的组合过滤重复记录,仅保留每组的第一条记录,但原有的分组代码未生效,无法得到预期的去重结果。
输入XML结构
<?xml version='1.0' encoding='UTF-8'?> <SyncFileResponse xmlns="http://xmlns.oracle.com/types"> <AFiles xmlns="http://TargetNamespace.com/fileReference"> <AFile> <DOC>DOC1</DOC> <DOCO>DOC1</DOCO> <DCTO>DCTO1</DCTO> <GRWT>GRWT1</GRWT> <GWUM>GWUM1</GWUM> <Column31>Column31616968</Column31> </AFile> <AFile> <DOC>DOC1</DOC> <DOCO>DOC1</DOCO> <DCTO>DCTO10</DCTO> <GRWT>GRWT10</GRWT> <GWUM>GWUM10</GWUM> <Column31>ABCD0</Column31> </AFile> <AFile> <DOC>DOC2</DOC> <DOCO>DOC2</DOCO> <DCTO>DCTO2</DCTO> <GRWT>GRWT2</GRWT> <GWUM>GWUM2</GWUM> <Column31>ABCD2</Column31> </AFile> <AFile> <DOC>DOC2</DOC> <DOCO>DOC2</DOCO> <DCTO>DCTO20</DCTO> <GRWT>GRWT20</GRWT> <GWUM>GWUM20</GWUM> <Column31>ABCD20</Column31> </AFile> </AFiles> </SyncFileResponse>
尝试的分组代码
<xsl:for-each-group select="$FileFromInprogress/nsmpr1:SyncFileResponse/ns20:AFiles/ns20:AFile" group-by="concat (ns20:DOC, ns20:DOCO )">
预期输出
<AFile> <DOC>DOC1</DOC> <DOCO>DOC1</DOCO> <DCTO>DCTO1</DCTO> <GRWT>GRWT1</GRWT> <GWUM>GWUM1</GWUM> <Column31>Column31616968</Column31> </AFile> <AFile> <DOC>DOC2</DOC> <DOCO>DOC2</DOCO> <DCTO>DCTO2</DCTO> <GRWT>GRWT2</GRWT> <GWUM>GWUM2</GWUM> <Column31>ABCD2</Column31> </AFile>
替代解决方案
方案1:使用多键分组(XSLT 2.0+,OIC支持)
原代码用concat拼接两个元素值分组,可能出现意外匹配(比如DOC="AB"+DOCO="CD"和DOC="A"+DOCO="BCD"会被判定为同一组),更可靠的方式是直接用多键分组:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:nsmpr1="http://xmlns.oracle.com/types" xmlns:ns20="http://TargetNamespace.com/fileReference" exclude-result-prefixes="nsmpr1 ns20"> <xsl:output method="xml" indent="yes"/> <xsl:template match="/"> <xsl:variable name="FileFromInprogress" select="."/> <xsl:for-each-group select="$FileFromInprogress/nsmpr1:SyncFileResponse/ns20:AFiles/ns20:AFile" group-by="(ns20:DOC, ns20:DOCO)"> <!-- 输出每组的第一个AFile元素 --> <xsl:copy-of select="current-group()[1]"/> </xsl:for-each-group> </xsl:template> </xsl:stylesheet>
方案2:Muenchian分组(兼容XSLT 1.0)
如果环境限制只能用XSLT 1.0,可以用Muenchian分组方法,先定义组合键再匹配唯一组:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:nsmpr1="http://xmlns.oracle.com/types" xmlns:ns20="http://TargetNamespace.com/fileReference" exclude-result-prefixes="nsmpr1 ns20"> <xsl:output method="xml" indent="yes"/> <!-- 定义基于DOC和DOCO组合的键,用分隔符避免拼接冲突 --> <xsl:key name="afile-key" match="ns20:AFile" use="concat(ns20:DOC, '|', ns20:DOCO)"/> <xsl:template match="/"> <xsl:variable name="FileFromInprogress" select="."/> <!-- 只选择每组的第一个节点 --> <xsl:for-each select="$FileFromInprogress/nsmpr1:SyncFileResponse/ns20:AFiles/ns20:AFile[generate-id() = generate-id(key('afile-key', concat(ns20:DOC, '|', ns20:DOCO))[1])]"> <xsl:copy-of select="."/> </xsl:for-each> </xsl:template> </xsl:stylesheet>
关键注意事项
- 必须确保XSLT头部的命名空间前缀
nsmpr1和ns20正确绑定到对应的URI,这是分组逻辑生效的核心前提。 - 多键分组(方案1)更直观且无拼接冲突风险,优先使用;Muenchian分组是XSLT 1.0环境下的经典解决方案。
内容的提问来源于stack exchange,提问作者kumarb
相关产品推荐
相关产品推荐

