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

XSLT 2.0分组转换XML时元素重复问题的解决诉求

解决XSLT分组转换中元素重复输出的问题

我来帮你搞定这个重复输出的问题~你遇到的核心问题是当前的节点选择逻辑存在重叠,导致同一批<p>元素被多次处理输出。

问题根源

你原来的XSLT中,处理heading-01时会选中它之后所有直到下一个heading-01的节点,其中包含heading-02和对应的paratext;而单独的heading-02模板又会处理自身和后续的paratext,把它们包装成<sec>,但同时这些paratext又会被默认的身份模板再输出一次,最终造成重复。

修改后的XSLT代码

推荐使用XSLT 2.0原生的xsl:for-each-group分组功能,通过group-starting-with明确划分层级,确保每个节点只被归属到一个分组,避免重复处理:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                xmlns:xs="http://www.w3.org/2001/XMLSchema" 
                exclude-result-prefixes="xs" 
                version="2.0">

    <!-- 默认身份模板:复制未被其他模板匹配的节点 -->
    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="body">
        <body>
            <!-- 第一层分组:以每个heading-01作为分组起始 -->
            <xsl:for-each-group select="node()" group-starting-with="p[@content-type='heading-01']">
                <xsl:if test="self::p[@content-type='heading-01']">
                    <sec sec-type="{@content-type}">
                        <title><xsl:value-of select="."/></title>
                        <!-- 第二层分组:在当前heading-01组内,以heading-02作为分组起始 -->
                        <xsl:for-each-group select="current-group() except ." group-starting-with="p[@content-type='heading-02']">
                            <xsl:choose>
                                <xsl:when test="self::p[@content-type='heading-02']">
                                    <sec sec-type="{@content-type}">
                                        <title><xsl:value-of select="."/></title>
                                        <!-- 输出当前heading-02组内的所有paratext -->
                                        <xsl:apply-templates select="current-group() except ."/>
                                    </sec>
                                </xsl:when>
                                <xsl:otherwise>
                                    <!-- 输出heading-01直接对应的paratext -->
                                    <xsl:apply-templates select="current-group()"/>
                                </xsl:otherwise>
                            </xsl:choose>
                        </xsl:for-each-group>
                    </sec>
                </xsl:if>
            </xsl:for-each-group>
        </body>
    </xsl:template>

</xsl:stylesheet>

代码逻辑说明

  1. 第一层分组:在<body>内,将所有节点以p[@content-type='heading-01']为起始分组,每个分组对应一个heading-01及其后续内容,直到下一个heading-01出现。
  2. 第二层分组:在每个heading-01的分组内,再以p[@content-type='heading-02']为起始划分子分组,确保每个heading-02和对应的paratext被单独包裹进子<sec>。
  3. 避免重复:每个节点只会属于一个分组,heading-02对应的paratext只会在子<sec>内输出一次,而heading-01直接对应的paratext也仅输出一次,彻底解决重复问题。

用这个代码处理你的输入XML,就能得到你期望的输出结果啦~

内容的提问来源于stack exchange,提问作者Amrendra Kumar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:42:58