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

XSLT:不改变节点顺序的表格分组与合并问题

XSLT 2.0 实现TABLE按TABLETHEAD文本分组并保留兄弟节点顺序

我明白你遇到的痛点——之前用Muenchian分组时,因为TABLE和IMAGE、GRAPHIC等节点同级交错,要么丢了兄弟节点,要么打乱了顺序。其实XSLT 2.0的for-each-group指令刚好能解决这种混合节点的分组需求,完美兼顾分组逻辑和原始节点的顺序、内容保留。

核心思路

我们要把父节点下的所有子节点分成两类组处理:

  • TABLE节点组:按TABLETHEAD的规范化文本内容分组,同一文本的TABLE合并成一个,保留一个表头、合并所有行
  • 非TABLE节点组:每个节点单独成组,保证它们的原始顺序和内容完全不变

完整XSLT示例

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" encoding="UTF-8"/>

    <!-- 匹配根节点,传递到父节点处理 -->
    <xsl:template match="/">
        <xsl:apply-templates select="*"/>
    </xsl:template>

    <!-- 匹配包含TABLE和其他兄弟节点的父节点(替换成你实际的父节点名称,比如DOC/CONTENT) -->
    <xsl:template match="*[node-name()='CONTENT']">
        <xsl:copy>
            <!-- 对所有子节点分组:TABLE按TABLETHEAD文本分组,其他节点单独成组 -->
            <xsl:for-each-group select="node()" group-by="
                if (self::TABLE) 
                then normalize-space(string(TABLETHEAD)) 
                else generate-id()
            ">
                <!-- 处理TABLE分组:合并成单个TABLE -->
                <xsl:if test="current-group()[self::TABLE]">
                    <TABLE>
                        <!-- 保留分组内第一个TABLE的TABLETHEAD(含所有子结构和属性) -->
                        <xsl:copy-of select="current-group()[1]/TABLETHEAD"/>
                        <!-- 合并分组内所有TABLE的TABLEROW -->
                        <xsl:copy-of select="current-group()/TABLEROW"/>
                    </TABLE>
                </xsl:if>

                <!-- 处理非TABLE分组:直接输出所有节点(包括文本、注释、空白节点) -->
                <xsl:if test="not(current-group()[self::TABLE])">
                    <xsl:copy-of select="current-group()"/>
                </xsl:if>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>

    <!-- 身份模板:确保未匹配的节点/属性原样保留 -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

关键细节说明

  1. 分组键的设计:

    • 对TABLE节点,用normalize-space(string(TABLETHEAD))作为分组键:normalize-space去除多余空格,string()确保即使TABLETHEAD包含子元素(比如<b>、<span>),也能获取完整文本内容,避免因格式差异导致分组错误。
    • 对非TABLE节点,用generate-id()作为分组键:每个节点生成唯一ID,保证每个非TABLE节点都是单独一组,不会被合并,完美保留原始顺序。
  2. TABLE合并逻辑:

    • 只保留分组内第一个TABLE的TABLETHEAD,避免重复表头
    • 把分组内所有TABLE的TABLEROW全部复制到新TABLE下,实现行合并
  3. 灵活调整:

    • 请把示例中的*[node-name()='CONTENT']替换成你实际的父节点名称(比如你的XML中TABLE的直接父节点是<DOC>就写成match="DOC")
    • 如果TABLETHEAD有特殊属性或子结构,copy-of会自动保留,无需额外处理

为什么这个方案能解决你的问题?

和Muenchian分组不同,for-each-group可以直接遍历所有类型的节点,不需要提前筛选TABLE,这样就能在分组的同时,自动保留所有非TABLE兄弟节点的位置和内容,完全不会打乱原始XML的节点顺序。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 10:35:41