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

如何用XSLT对满足colspan条件的连续ENTRY元素分组并添加属性

XSLT实现表格连续列合并(添加NAMEST/NAMEEND属性)

需求说明

需要为XML表格中满足以下条件的ENTRY元素添加NAMEST和NAMEEND属性:

  • 该元素后面跟着连续的一个或多个CONTENT值为##colspan##的ENTRY元素
  • NAMEST属性值为合并列的起始列名(当前元素的COLNAME)
  • NAMEEND属性值为合并列的结束列名(连续##colspan##元素的最后一个的COLNAME)
  • 同时移除所有CONTENT值为##colspan##的ENTRY元素

当前XML表格

<TABLE>
  <ROW>
     <ENTRY COLNUM="1" COLNAME="col1">
        <CONTENT>42</CONTENT>
     </ENTRY>
     <ENTRY COLNUM="2" COLNAME="col2">
        <CONTENT>155</CONTENT>
     </ENTRY>
     <ENTRY COLNUM="3" COLNAME="col3">
        <CONTENT></CONTENT>
     </ENTRY>
     <ENTRY COLNUM="4" COLNAME="col4">
        <CONTENT>##colspan##</CONTENT>
     </ENTRY>
     <ENTRY COLNUM="5" COLNAME="col5">
        <CONTENT>##colspan##</CONTENT>
     </ENTRY>
     <ENTRY COLNUM="6" COLNAME="col6">
        <CONTENT>##colspan##</CONTENT>
     </ENTRY>
  </ROW>
  <ROW>
     <ENTRY COLNUM="1" COLNAME="col1">
        <CONTENT>147</CONTENT>
     </ENTRY>
     <ENTRY COLNUM="2" COLNAME="col2">
        <CONTENT>jalla</CONTENT>
     </ENTRY>
     <ENTRY COLNUM="3" COLNAME="col3">
        <CONTENT/>
     </ENTRY>
     <ENTRY COLNUM="4" COLNAME="col4">
        <CONTENT>##colspan##</CONTENT>
     </ENTRY>
     <ENTRY COLNUM="5" COLNAME="col5">
        <CONTENT/>
     </ENTRY>
     <ENTRY COLNUM="6" COLNAME="col6">
        <CONTENT>##colspan##</CONTENT>
     </ENTRY>
  </ROW>
  <ROW>
     <ENTRY COLNUM="1" COLNAME="col1">
        <CONTENT>147</CONTENT>
     </ENTRY>
     <ENTRY COLNUM="2" COLNAME="col2">
        <CONTENT>##colspan##</CONTENT>
     </ENTRY>
     <ENTRY COLNUM="3" COLNAME="col3">
        <CONTENT/>
     </ENTRY>
     <ENTRY COLNUM="4" COLNAME="col4">
        <CONTENT>300</CONTENT>
     </ENTRY>
     <ENTRY COLNUM="5" COLNAME="col5">
        <CONTENT>##colspan##</CONTENT>
     </ENTRY>
     <ENTRY COLNUM="6" COLNAME="col6">
        <CONTENT>##colspan##</CONTENT>
     </ENTRY>
  </ROW>
  <ROW>
     <ENTRY COLNUM="1" COLNAME="col1">
        <CONTENT>1814</CONTENT>
     </ENTRY>
     <ENTRY COLNUM="2" COLNAME="col2">
        <CONTENT>##colspan##</CONTENT>
     </ENTRY>
     <ENTRY COLNUM="3" COLNAME="col3">
        <CONTENT>##colspan##</CONTENT>
     </ENTRY>
     <ENTRY COLNUM="4" COLNAME="col4">
        <CONTENT>1905</CONTENT>
     </ENTRY>
     <ENTRY COLNUM="5" COLNAME="col5">
        <CONTENT/>
     </ENTRY>
     <ENTRY COLNUM="6" COLNAME="col6">
        <CONTENT>##colspan##</CONTENT>
     </ENTRY>
  </ROW>
  <ROW>
     <ENTRY COLNUM="1" COLNAME="col1">
        <CONTENT>##colspan##</CONTENT>
     </ENTRY>
     <ENTRY COLNUM="2" COLNAME="col2">
        <CONTENT/>
     </ENTRY>
     <ENTRY COLNUM="3" COLNAME="col3">
        <CONTENT/>
     </ENTRY>
     <ENTRY COLNUM="4" COLNAME="col4">
        <CONTENT>##colspan##</CONTENT>
     </ENTRY>
     <ENTRY COLNUM="5" COLNAME="col5">
        <CONTENT/>
     </ENTRY>
     <ENTRY COLNUM="6" COLNAME="col6">
        <CONTENT>##colspan##</CONTENT>
     </ENTRY>
  </ROW>
</TABLE>

期望输出XML

<TABLE DEFINITION="false">
  <ROW>
     <ENTRY COLNUM="1" COLNAME="col1">
        <CONTENT>42</CONTENT>
     </ENTRY>
     <ENTRY COLNUM="2" COLNAME="col2">
        <CONTENT>155</CONTENT>
     </ENTRY>
     <ENTRY NAMEST="col3" NAMEEND="col6" COLNUM="3" COLNAME="col3">
        <CONTENT/>
     </ENTRY>
  </ROW>
  <ROW>
     <ENTRY COLNUM="1" COLNAME="col1">
        <CONTENT>147</CONTENT>
     </ENTRY>
     <ENTRY COLNUM="2" COLNAME="col2">
        <CONTENT>155</CONTENT>
     </ENTRY>
     <ENTRY NAMEST="col3" NAMEEND="col4" COLNUM="3" COLNAME="col3">
        <CONTENT/>
     </ENTRY>
     <ENTRY NAMEST="col5" NAMEEND="col6" COLNUM="5" COLNAME="col5">
        <CONTENT/>
     </ENTRY>
  </ROW>
  <ROW>
     <ENTRY NAMEST="col1" NAMEEND="col2" COLNUM="1" COLNAME="col1">
        <CONTENT>147</CONTENT>
     </ENTRY>
     <ENTRY COLNUM="3" COLNAME="col3">
        <CONTENT/>
     </ENTRY>
     <ENTRY NAMEST="col4" NAMEEND="col6" COLNUM="4" COLNAME="col4">
        <CONTENT>300</CONTENT>
     </ENTRY>
  </ROW>
  <ROW>
     <ENTRY NAMEST="col1" NAMEEND="col3" COLNUM="1" COLNAME="col1">
        <CONTENT>1814</CONTENT>
     </ENTRY>
     <ENTRY COLNUM="4" COLNAME="col4">
        <CONTENT>1905</CONTENT>
     </ENTRY>
     <ENTRY NAMEST="col5" NAMEEND="col6" COLNUM="5" COLNAME="col5">
        <CONTENT/>
     </ENTRY>
  </ROW>
  <ROW>
     <ENTRY COLNUM="1" COLNAME="col1">
        <CONTENT>##colspan##</CONTENT>
     </ENTRY>
     <ENTRY COLNUM="2" COLNAME="col2">
        <CONTENT/>
     </ENTRY>
     <ENTRY NAMEST="col3" NAMEEND="col4" COLNUM="3" COLNAME="col3">
        <CONTENT/>
     </ENTRY>
     <ENTRY NAMEST="col5" NAMEEND="col6" COLNUM="5" COLNAME="col5">
        <CONTENT/>
     </ENTRY>
  </ROW>
</TABLE>

尝试的XSLT代码(存在问题)

<xsl:variable name="colspanText" as="xs:string" select="'##colspan##'"/>

<xsl:template match="ENTRY">

    <xsl:variable name="myColName" as="xs:string" select="@COLNAME"/>

    <!-- Keep all ENTRY elements except those with ##colspan## in CONTENT. Element #1 should always be kept though. -->

    <xsl:if test="not(CONTENT = $colspanText and not(position() = 2))">
        <xsl:copy>

            <!-- Add NAMEST and NAMEEND parameters if we have a colspan -->

            <xsl:for-each-group
                select="following-sibling::ENTRY" group-adjacent="CONTENT = $colspanText">
                <xsl:if test="current-grouping-key()">
                    <xsl:attribute name="NAMEST"  select="$myColName"/>
                    <xsl:attribute name="NAMEEND" select="@COLNAME"  />
                </xsl:if>
            </xsl:for-each-group>
            
            
            <!-- Copy everything else -->
            <xsl:apply-templates select="@* | node()"/>

        </xsl:copy>
    </xsl:if>

</xsl:template>

解决方案(正确的XSLT代码)

使用XSLT 2.0+的分组功能,按ROW分组后,对每个ROW内的ENTRY以非##colspan##的元素为分组起始,将后续连续的##colspan##元素归为同一组,再为起始元素添加合并属性:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
    
    <xsl:variable name="colspanText" as="xs:string" select="'##colspan##'"/>
    
    <!-- 复制所有节点和属性,除非有专门的模板匹配 -->
    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>
    
    <!-- 处理TABLE元素,添加DEFINITION属性 -->
    <xsl:template match="TABLE">
        <TABLE DEFINITION="false">
            <xsl:apply-templates/>
        </TABLE>
    </xsl:template>
    
    <!-- 处理ROW元素,对ENTRY进行分组处理 -->
    <xsl:template match="ROW">
        <ROW>
            <!-- 分组规则:以非##colspan##的ENTRY为起始,后续连续的##colspan##元素归为同一组 -->
            <xsl:for-each-group select="ENTRY" group-starting-with="ENTRY[not(CONTENT = $colspanText)]">
                <!-- 复制起始的ENTRY元素 -->
                <xsl:copy>
                    <!-- 如果组内除了起始元素还有其他元素(即存在连续的##colspan##),添加合并属性 -->
                    <xsl:if test="count(current-group()) > 1">
                        <xsl:attribute name="NAMEST" select="@COLNAME"/>
                        <xsl:attribute name="NAMEEND" select="current-group()[last()]/@COLNAME"/>
                    </xsl:if>
                    <!-- 复制原有的属性和子节点 -->
                    <xsl:apply-templates select="@* | node()"/>
                </xsl:copy>
            </xsl:for-each-group>
            
            <!-- 单独处理那些本身是##colspan##的ENTRY(不在任何起始组里的) -->
            <xsl:apply-templates select="ENTRY[CONTENT = $colspanText][not(preceding-sibling::ENTRY[1][not(CONTENT = $colspanText)])]"/>
        </ROW>
    </xsl:template>
    
    <!-- 忽略所有##colspan##的ENTRY,除非是单独存在的(上面的模板已经处理) -->
    <xsl:template match="ENTRY[CONTENT = $colspanText]"/>
    
</xsl:stylesheet>

代码说明

  1. 基础复制模板:默认复制所有节点和属性,保证非目标元素的结构不变。
  2. TABLE模板:为TABLE元素添加DEFINITION="false"属性,匹配期望输出。
  3. ROW模板:
    • 使用group-starting-with将ENTRY分组,每个组以非##colspan##的元素开头,后续连续的##colspan##元素归入同一组。
    • 对每个组的起始元素,若组内有多个元素,添加NAMEST和NAMEEND属性,分别取起始元素和组内最后一个元素的COLNAME。
    • 单独处理那些本身是##colspan##且前面没有非##colspan##元素的ENTRY(如第五行的col1),保留其原结构。
  4. 忽略模板:默认忽略所有CONTENT为##colspan##的ENTRY,避免重复输出。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 09:25:57