XSLT分组逻辑修正:K18/P01分组及无TP1的P01保留问题
修正XSLT以保留无TP1的P01节点并实现指定分组逻辑
需求概述
- 对
K18节点按ALF和OND字段分组,同组节点的P04Y、P04Z、P04、P03子段按P04Y→P04Z→P04→P03的顺序合并(所有子段均为非必填) - 对
P01节点下的TP1子节点按ID和RAS字段分组,将同组的PT2子段合并到同一个TP1节点下;若P01无TP1子节点,需原样保留该P01节点(TP1为非必填)
问题
当前使用的XSLT会删除不含TP1子节点的P01节点,需要修正该问题,同时确保上述两项分组逻辑正确执行。
输入示例
<Root> <K18 ALF="A" OND="1"> <P04Y>Y1</P04Y> <P03>3A1</P03> </K18> <K18 ALF="A" OND="1"> <P04Z>Z1</P04Z> <P04>4A1</P04> </K18> <P01> <SomeData>Data1</SomeData> <!-- 无TP1节点 --> </P01> <P01> <TP1 ID="T1" RAS="R1"> <PT2>PT2-1</PT2> </TP1> <TP1 ID="T1" RAS="R1"> <PT2>PT2-2</PT2> </TP1> </P01> </Root>
期望输出
<Root> <K18 ALF="A" OND="1"> <P04Y>Y1</P04Y> <P04Z>Z1</P04Z> <P04>4A1</P04> <P03>3A1</P03> </K18> <P01> <SomeData>Data1</SomeData> </P01> <P01> <TP1 ID="T1" RAS="R1"> <PT2>PT2-1</PT2> <PT2>PT2-2</PT2> </TP1> </P01> </Root>
现有问题XSLT
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <!-- 分组处理K18 --> <xsl:template match="K18"> <xsl:for-each-group select="." group-by="concat(ALF, '|', OND)"> <K18 ALF="{current-grouping-key()}" OND="{current-grouping-key()}"> <xsl:copy-of select="current-group()/P04Y"/> <xsl:copy-of select="current-group()/P04Z"/> <xsl:copy-of select="current-group()/P04"/> <xsl:copy-of select="current-group()/P03"/> </K18> </xsl:for-each-group> </xsl:template> <!-- 仅处理含TP1的P01 --> <xsl:template match="P01[TP1]"> <P01> <xsl:copy-of select="*[not(self::TP1)]"/> <xsl:for-each-group select="TP1" group-by="concat(ID, '|', RAS)"> <TP1 ID="{ID}" RAS="{RAS}"> <xsl:copy-of select="current-group()/PT2"/> </TP1> </xsl:for-each-group> </P01> </xsl:template> </xsl:stylesheet>
修正后的XSLT
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <!-- 默认身份模板:保留所有未自定义匹配的节点/属性 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- 分组处理K18节点 --> <xsl:template match="K18"> <xsl:for-each-group select="." group-by="concat(ALF, '|', OND)"> <K18 ALF="{substring-before(current-grouping-key(), '|')}" OND="{substring-after(current-grouping-key(), '|')}" > <!-- 按指定顺序合并子段 --> <xsl:copy-of select="current-group()/P04Y"/> <xsl:copy-of select="current-group()/P04Z"/> <xsl:copy-of select="current-group()/P04"/> <xsl:copy-of select="current-group()/P03"/> </K18> </xsl:for-each-group> </xsl:template> <!-- 处理所有P01节点(含无TP1的情况) --> <xsl:template match="P01"> <P01> <!-- 复制除TP1外的所有子节点 --> <xsl:copy-of select="*[not(self::TP1)]"/> <!-- 仅当存在TP1时执行分组逻辑 --> <xsl:if test="TP1"> <xsl:for-each-group select="TP1" group-by="concat(ID, '|', RAS)"> <TP1 ID="{substring-before(current-grouping-key(), '|')}" RAS="{substring-after(current-grouping-key(), '|')}" > <xsl:copy-of select="current-group()/PT2"/> </TP1> </xsl:for-each-group> </xsl:if> </P01> </xsl:template> </xsl:stylesheet>
关键修改说明
- 添加默认身份模板:确保所有未被自定义模板匹配的节点(包括无TP1的P01)都会被原样保留,避免被XSLT默认模板跳过。
- 调整P01匹配范围:将模板匹配条件从
P01[TP1]改为P01,覆盖所有P01节点;通过<xsl:if test="TP1">仅在存在TP1时执行分组逻辑,无TP1时直接复制其他子节点。 - 修正K18属性赋值:原代码错误地将完整分组键赋值给ALF和OND,修正为用
substring-before和substring-after拆分分组键,正确提取原始字段值。
内容的提问来源于stack exchange,提问作者CHAR
相关产品推荐
相关产品推荐

